diff --git a/codxe.vcxproj b/codxe.vcxproj index 59dc162..0c208ef 100644 --- a/codxe.vcxproj +++ b/codxe.vcxproj @@ -129,6 +129,7 @@ + @@ -256,6 +257,7 @@ + diff --git a/src/game/iw4/mp_tu6/components/cmds.cpp b/src/game/iw4/mp_tu6/components/cmds.cpp new file mode 100644 index 0000000..67a8fd4 --- /dev/null +++ b/src/game/iw4/mp_tu6/components/cmds.cpp @@ -0,0 +1,90 @@ +#include "pch.h" +#include "cmds.h" + +namespace iw4 +{ +namespace mp_tu6 +{ +namespace +{ + +Detour ClientCommand_Detour; + +void SendCommandMessage(int clientNum, const char *message) +{ + const char *commandString = va("%c \"%s\"", 101, message); + + SV_GameSendServerCommand(clientNum, SV_CMD_CAN_IGNORE, commandString); +} + +bool ToggleFlag(int &flags, int flag) +{ + const bool enableFlag = (flags & flag) == 0; + + if (enableFlag) + flags |= flag; + else + flags &= ~flag; + + return enableFlag; +} + +void Cmd_Noclip_f(int clientNum, gentity_s *ent) +{ + const bool enabled = ToggleFlag(ent->client->flags, CF_NOCLIP); + SendCommandMessage(clientNum, enabled ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF"); +} + +void Cmd_UFO_f(int clientNum, gentity_s *ent) +{ + const bool enabled = ToggleFlag(ent->client->flags, CF_UFO); + SendCommandMessage(clientNum, enabled ? "GAME_UFOON" : "GAME_UFOOFF"); +} + +void Cmd_God_f(int clientNum, gentity_s *ent) +{ + const bool enabled = ToggleFlag(ent->flags, FL_GODMODE); + SendCommandMessage(clientNum, enabled ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF"); +} + +void Cmd_DemiGod_f(int clientNum, gentity_s *ent) +{ + const bool enabled = ToggleFlag(ent->flags, FL_DEMI_GODMODE); + SendCommandMessage(clientNum, enabled ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF"); +} + +void ClientCommand_Hook(int clientNum) +{ + assert(clientNum >= 0 && clientNum < IW4_MAX_CLIENTS); + + gentity_s *ent = &g_entities[clientNum]; + assert(ent->client); + + char cmd[1024] = {}; + SV_Cmd_ArgvBuffer(0, cmd, static_cast(sizeof(cmd))); + + if (I_stricmp(cmd, "god") == 0) + Cmd_God_f(clientNum, ent); + else if (I_stricmp(cmd, "demigod") == 0) + Cmd_DemiGod_f(clientNum, ent); + else if (I_stricmp(cmd, "noclip") == 0) + Cmd_Noclip_f(clientNum, ent); + else if (I_stricmp(cmd, "ufo") == 0) + Cmd_UFO_f(clientNum, ent); + else + ClientCommand_Detour.GetOriginal()(clientNum); +} +} // namespace + +cmds::cmds() +{ + ClientCommand_Detour = Detour(ClientCommand, ClientCommand_Hook); + ClientCommand_Detour.Install(); +} + +cmds::~cmds() +{ + ClientCommand_Detour.Remove(); +} +} // namespace mp_tu6 +} // namespace iw4 diff --git a/src/game/iw4/mp_tu6/components/cmds.h b/src/game/iw4/mp_tu6/components/cmds.h new file mode 100644 index 0000000..2a8582d --- /dev/null +++ b/src/game/iw4/mp_tu6/components/cmds.h @@ -0,0 +1,21 @@ +#pragma once + +#include "pch.h" + +namespace iw4 +{ +namespace mp_tu6 +{ +class cmds : public Module +{ + public: + cmds(); + ~cmds(); + + const char *get_name() override + { + return "cmds"; + }; +}; +} // namespace mp_tu6 +} // namespace iw4 diff --git a/src/game/iw4/mp_tu6/main.cpp b/src/game/iw4/mp_tu6/main.cpp index ff9f3f4..5cca696 100644 --- a/src/game/iw4/mp_tu6/main.cpp +++ b/src/game/iw4/mp_tu6/main.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "components/cg.h" #include "components/clipmap.h" +#include "components/cmds.h" #include "components/console.h" #include "components/events.h" #include "components/g_client_fields.h" @@ -25,6 +26,7 @@ IW4_MP_TU6_Plugin::IW4_MP_TU6_Plugin() RegisterModule(new Events()); // Must be registered first to ensure hooks are in place RegisterModule(new cg()); RegisterModule(new clipmap()); + RegisterModule(new cmds()); RegisterModule(new console()); RegisterModule(new g_client_fields()); RegisterModule(new g_scr_main()); diff --git a/src/game/iw4/mp_tu6/structs.h b/src/game/iw4/mp_tu6/structs.h index 0957b31..244b66c 100644 --- a/src/game/iw4/mp_tu6/structs.h +++ b/src/game/iw4/mp_tu6/structs.h @@ -56,6 +56,12 @@ enum DvarFlags : std::uint16_t DVAR_FLAG_SERVERINFO = 0x10, }; +enum svscmd_type : __int32 +{ + SV_CMD_CAN_IGNORE = 0x0, + SV_CMD_RELIABLE = 0x1, +}; + struct dvar_t { const char *name; @@ -826,6 +832,37 @@ struct blend_ent_t float totalTime; }; +enum entityFlag_t : uint32_t +{ + FL_GODMODE = 0x1, + FL_DEMI_GODMODE = 0x2, + FL_NOTARGET = 0x4, + FL_NO_KNOCKBACK = 0x8, + FL_NO_RADIUS_DAMAGE = 0x10, + FL_SUPPORTS_LINKTO = 0x1000, + FL_NO_AUTO_ANIM_UPDATE = 0x2000, + FL_GRENADE_TOUCH_DAMAGE = 0x4000, + FL_STABLE_MISSILES = 0x20000, + FL_REPEAT_ANIM_UPDATE = 0x40000, + FL_VEHICLE_TARGET = 0x80000, + FL_GROUND_ENT = 0x100000, + FL_CURSOR_HINT = 0x200000, + FL_MISSILE_ATTRACTOR = 0x800000, + FL_WEAPON_BEING_GRABBED = 0x1000000, + FL_DELETE = 0x2000000, + FL_BOUNCE = 0x4000000, + FL_MOVER_SLIDE = 0x8000000, +}; + +enum clientFlag_t : uint32_t +{ + CF_NOCLIP = 1u << 0, + CF_UFO = 1u << 1, + CF_FROZEN = 1u << 2, + CF_DISABLE_USABILITY = 1u << 3, + CF_NO_KNOCKBACK = 1u << 4, +}; + struct gentity_s { entityState_s s; @@ -1772,7 +1809,12 @@ enum XAssetType : __int32 struct cplane_s; struct cStaticModel_s; -struct ClipMaterial; +struct ClipMaterial +{ + const char *name; + int surfaceFlags; + int contentFlags; +}; struct cbrushside_t; struct cNode_t; struct cLeaf_t; diff --git a/src/game/iw4/mp_tu6/symbols.h b/src/game/iw4/mp_tu6/symbols.h index 233ebd9..ee6e7c7 100644 --- a/src/game/iw4/mp_tu6/symbols.h +++ b/src/game/iw4/mp_tu6/symbols.h @@ -21,6 +21,9 @@ static auto Hunk_AllocateTempMemoryHighInternal = reinterpret_cast(0x82275C60); +typedef void (*ClientCommand_t)(int clientNum); +static ClientCommand_t ClientCommand = reinterpret_cast(0x822266D0); + typedef void (*CL_CharEvent_t)(int localClientNum, int key); static CL_CharEvent_t CL_CharEvent = reinterpret_cast(0x82182EC8); @@ -53,6 +56,9 @@ static Com_Printf_t Com_Printf = reinterpret_cast(0x8227F448); typedef void (*Com_PrintMessage_t)(int channel, const char *msg, int error); static Com_PrintMessage_t Com_PrintMessage = reinterpret_cast(0x8227F370); +typedef int (*I_stricmp_t)(const char *s0, const char *s1); +static I_stricmp_t I_stricmp = reinterpret_cast(0x82315B70); + typedef void (*Info_SetValueForKey_t)(char *s, const char *key, const char *value); static Info_SetValueForKey_t Info_SetValueForKey = reinterpret_cast(0x823167D8); @@ -216,6 +222,12 @@ static SV_IsClientBot_t SV_IsClientBot = reinterpret_cast(0x82 typedef gentity_s *(*SV_AddTestClient_t)(); static SV_AddTestClient_t SV_AddTestClient = reinterpret_cast(0x822BDCB8); +typedef void (*SV_Cmd_ArgvBuffer_t)(int arg, char *buffer, int bufferLength); +static SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer = reinterpret_cast(0x822760C8); + +typedef void (*SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char *text); +static SV_GameSendServerCommand_t SV_GameSendServerCommand = reinterpret_cast(0x822BDF00); + typedef void (*SV_UserinfoChanged_t)(client_t *cl); static SV_UserinfoChanged_t SV_UserinfoChanged = reinterpret_cast(0x822BBED8);