Add sp commands

This commit is contained in:
FutureRave 2022-03-11 14:30:00 +00:00
parent be159107b7
commit 6251a1d5ac
No known key found for this signature in database
GPG Key ID: E883E2BC9657D955
6 changed files with 273 additions and 8 deletions

View File

@ -13,6 +13,8 @@ namespace game
DB_LoadXAssets_t DB_LoadXAssets; DB_LoadXAssets_t DB_LoadXAssets;
Dvar_SetIntByName_t Dvar_SetIntByName;
Dvar_SetFromStringByName_t Dvar_SetFromStringByName; Dvar_SetFromStringByName_t Dvar_SetFromStringByName;
G_RunFrame_t G_RunFrame; G_RunFrame_t G_RunFrame;
@ -53,6 +55,8 @@ namespace game
XUIDToString_t XUIDToString; XUIDToString_t XUIDToString;
SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
decltype(longjmp)* _longjmp; decltype(longjmp)* _longjmp;
CmdArgs* sv_cmd_args; CmdArgs* sv_cmd_args;
@ -88,6 +92,11 @@ namespace game
client_t* svs_clients; client_t* svs_clients;
} }
namespace sp
{
sp::gentity_s* g_entities;
}
void AddRefToValue(VariableValue* value) void AddRefToValue(VariableValue* value)
{ {
if (value->type == SCRIPT_OBJECT) if (value->type == SCRIPT_OBJECT)
@ -539,6 +548,18 @@ namespace game
(0x50D840)(player, origin, angles); (0x50D840)(player, origin, angles);
} }
} }
void CG_GameMessage(LocalClientNum_t localClientNum, const char* msg)
{
if (is_mp())
{
reinterpret_cast<void(*)(LocalClientNum_t, const char*)>(0x456DC0)(localClientNum, msg);
}
else if (is_sp())
{
reinterpret_cast<void(*)(LocalClientNum_t, const char*, int /*flags*/)>(0x4228A0)(localClientNum, msg, 17);
}
}
} }
launcher::mode mode = launcher::mode::none; launcher::mode mode = launcher::mode::none;
@ -580,6 +601,8 @@ namespace game
native::DB_LoadXAssets = native::DB_LoadXAssets_t(SELECT_VALUE(0x48A8E0, 0x4CD020, 0x44F770)); native::DB_LoadXAssets = native::DB_LoadXAssets_t(SELECT_VALUE(0x48A8E0, 0x4CD020, 0x44F770));
native::Dvar_SetIntByName = native::Dvar_SetIntByName_t(SELECT_VALUE(0x5396B0, 0x5BF560, 0x0));
native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t( native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t(
SELECT_VALUE(0x4DD090, 0x5BF740, 0x518DF0)); SELECT_VALUE(0x4DD090, 0x5BF740, 0x518DF0));
@ -595,7 +618,7 @@ namespace game
native::Scr_AddEntityNum = native::Scr_AddEntityNum_t(SELECT_VALUE(0x0, 0x56ABC0, 0x4EA2F0)); native::Scr_AddEntityNum = native::Scr_AddEntityNum_t(SELECT_VALUE(0x0, 0x56ABC0, 0x4EA2F0));
native::Scr_Notify = native::Scr_Notify_t(SELECT_VALUE(0x0, 0x52B190, 0x0)); native::Scr_Notify = native::Scr_Notify_t(SELECT_VALUE(0x4895B0, 0x52B190, 0x0));
native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590, 0)); native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590, 0));
@ -617,15 +640,18 @@ namespace game
native::SV_Cmd_EndTokenizedString = native::SV_Cmd_EndTokenizedString_t(SELECT_VALUE(0x0, 0x545D70, 0x0)); native::SV_Cmd_EndTokenizedString = native::SV_Cmd_EndTokenizedString_t(SELECT_VALUE(0x0, 0x545D70, 0x0));
native::SV_GameSendServerCommand = native::SV_GameSendServerCommand_t(SELECT_VALUE(0x0, 0x573220, 0x0)); native::SV_GameSendServerCommand = native::SV_GameSendServerCommand_t(SELECT_VALUE(0x402130, 0x573220, 0x0));
native::SV_SendServerCommand = native::SV_SendServerCommand_t(SELECT_VALUE(0x0, 0x575DE0, 0x4FD5A0)); native::SV_SendServerCommand = native::SV_SendServerCommand_t(SELECT_VALUE(0x4F6990, 0x575DE0, 0x4FD5A0));
native::XUIDToString = native::XUIDToString_t(SELECT_VALUE(0x4FAA30, 0x55CC20, 0x0)); native::XUIDToString = native::XUIDToString_t(SELECT_VALUE(0x4FAA30, 0x55CC20, 0x0));
native::SEH_LocalizeTextMessage = native::SEH_LocalizeTextMessage_t(
SELECT_VALUE(0x41EA20, 0x57E240, 0x0));
native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC, 0x655558)); native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC, 0x655558));
native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x0, 0x1CAA998, 0x1B5E7D8)); native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1757218, 0x1CAA998, 0x1B5E7D8));
native::cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1750750, 0x1C978D0, 0x1B455F8)); native::cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1750750, 0x1C978D0, 0x1B455F8));
native::scrVarGlob = reinterpret_cast<short*>(SELECT_VALUE(0x19AFC80, 0x1E72180, 0x1D3C800)); native::scrVarGlob = reinterpret_cast<short*>(SELECT_VALUE(0x19AFC80, 0x1E72180, 0x1D3C800));
@ -653,5 +679,6 @@ namespace game
native::dedi::svs_clients = reinterpret_cast<native::dedi::client_t*>(0x4A12E90); native::dedi::svs_clients = reinterpret_cast<native::dedi::client_t*>(0x4A12E90);
native::g_entities = reinterpret_cast<native::gentity_s*>(SELECT_VALUE(0, 0x1A66E28, 0x191B900)); native::g_entities = reinterpret_cast<native::gentity_s*>(SELECT_VALUE(0, 0x1A66E28, 0x191B900));
native::sp::g_entities = reinterpret_cast<native::sp::gentity_s*>(0x1197AD8);
} }
} }

View File

@ -23,6 +23,9 @@ namespace game
typedef void (*DB_LoadXAssets_t)(XZoneInfo* zoneInfo, unsigned int zoneCount, int sync); typedef void (*DB_LoadXAssets_t)(XZoneInfo* zoneInfo, unsigned int zoneCount, int sync);
extern DB_LoadXAssets_t DB_LoadXAssets; extern DB_LoadXAssets_t DB_LoadXAssets;
typedef void (*Dvar_SetIntByName_t)(const char* dvarName, int value);
extern Dvar_SetIntByName_t Dvar_SetIntByName;
typedef void (*Dvar_SetFromStringByName_t)(const char* dvarName, const char* string); typedef void (*Dvar_SetFromStringByName_t)(const char* dvarName, const char* string);
extern Dvar_SetFromStringByName_t Dvar_SetFromStringByName; extern Dvar_SetFromStringByName_t Dvar_SetFromStringByName;
@ -83,6 +86,9 @@ namespace game
typedef void (*XUIDToString_t)(const unsigned __int64* xuid, char* str); typedef void (*XUIDToString_t)(const unsigned __int64* xuid, char* str);
extern XUIDToString_t XUIDToString; extern XUIDToString_t XUIDToString;
typedef char* (*SEH_LocalizeTextMessage_t)(const char* pszInputBuffer, const char* pszMessageType, msgLocErrType_t errType);
extern SEH_LocalizeTextMessage_t SEH_LocalizeTextMessage;
extern decltype(longjmp)* _longjmp; extern decltype(longjmp)* _longjmp;
constexpr auto CMD_MAX_NESTING = 8; constexpr auto CMD_MAX_NESTING = 8;
@ -119,6 +125,11 @@ namespace game
extern client_t* svs_clients; extern client_t* svs_clients;
} }
namespace sp
{
extern sp::gentity_s* g_entities;
}
void AddRefToValue(VariableValue* value); void AddRefToValue(VariableValue* value);
void Conbuf_AppendText(const char* message); void Conbuf_AppendText(const char* message);
@ -156,6 +167,8 @@ namespace game
void Cbuf_AddText(LocalClientNum_t localClientNum, const char* text); void Cbuf_AddText(LocalClientNum_t localClientNum, const char* text);
void TeleportPlayer(gentity_s* player, float* origin, float* angles); void TeleportPlayer(gentity_s* player, float* origin, float* angles);
void CG_GameMessage(LocalClientNum_t localClientNum, const char* msg);
} }
bool is_mp(); bool is_mp();

View File

@ -391,6 +391,12 @@ namespace game
LOCAL_CLIENT_INVALID = -1, LOCAL_CLIENT_INVALID = -1,
}; };
enum msgLocErrType_t
{
LOCMSG_SAFE,
LOCMSG_NOERR,
};
struct cmd_function_t struct cmd_function_t
{ {
cmd_function_t* next; cmd_function_t* next;
@ -578,6 +584,12 @@ namespace game
dvar_t* hashNext; dvar_t* hashNext;
}; };
struct Bounds
{
float midPoint[3];
float halfSize[3];
};
struct usercmd_s struct usercmd_s
{ {
int serverTime; int serverTime;
@ -638,6 +650,26 @@ namespace game
FL_MOVER_SLIDE = 0x8000000 FL_MOVER_SLIDE = 0x8000000
}; };
enum entityType
{
ET_GENERAL,
ET_PLAYER,
ET_ITEM,
ET_MISSILE,
ET_INVISIBLE,
ET_SCRIPTMOVER,
ET_SOUND_BLEND,
ET_PRIMARY_LIGHT,
ET_TURRET,
ET_VEHICLE,
ET_VEHICLE_COLLMAP,
ET_VEHICLE_CORPSE,
ET_VEHICLE_SPAWNER,
ET_ACTOR,
ET_ACTOR_SPAWNER,
ET_ACTOR_CORPSE,
};
struct entityState_s struct entityState_s
{ {
int number; int number;
@ -792,5 +824,61 @@ namespace game
static_assert(sizeof(dedi::client_t) == 0x78690); static_assert(sizeof(dedi::client_t) == 0x78690);
} }
namespace sp
{
struct gclient_s
{
unsigned char __pad0[0xAE04];
int flags;
}; // Warning, incorrect size
struct entityState_s
{
int eType;
unsigned char __pad0[0x80];
int number;
unsigned char __pad1[0x28];
};
static_assert(sizeof(entityState_s) == 0xB0);
struct entityShared_t
{
unsigned __int8 isLinked;
unsigned __int8 modelType;
unsigned __int8 svFlags;
unsigned __int8 eventType;
unsigned __int8 isInUse;
Bounds box;
int contents;
Bounds absBox;
float currentOrigin[3];
float currentAngles[3];
EntHandle ownerNum;
int eventTime;
};
static_assert(sizeof(entityShared_t) == 0x5C);
struct gentity_s
{
entityState_s s;
entityShared_t r;
sp::gclient_s* client; // 0x10C
unsigned char __pad0[0x2C];
int flags;
int clipmask;
int processedFrame;
EntHandle parent;
int nextthink;
int health;
int maxHealth;
int damage;
unsigned char __pad1[0x114];
};
static_assert(sizeof(gentity_s) == 0x270);
}
} }
} }

View File

@ -26,7 +26,7 @@ private:
game::native::SV_SendServerCommand(&game::native::dedi::svs_clients[client_num], game::native::SV_SendServerCommand(&game::native::dedi::svs_clients[client_num],
type, string); type, string);
} }
else if (game::is_mp()) else
{ {
game::native::SV_GameSendServerCommand(client_num, type, string); game::native::SV_GameSendServerCommand(client_num, type, string);
} }

View File

@ -7,6 +7,7 @@
utils::memory::allocator command::allocator_; utils::memory::allocator command::allocator_;
std::unordered_map<std::string, std::function<void(const command::params&)>> command::handlers; std::unordered_map<std::string, std::function<void(const command::params&)>> command::handlers;
std::unordered_map<std::string, std::function<void(game::native::gentity_s*, command::params_sv&)>> command::handlers_sv; std::unordered_map<std::string, std::function<void(game::native::gentity_s*, command::params_sv&)>> command::handlers_sv;
std::unordered_map<std::string, std::function<void(game::native::sp::gentity_s*, command::params_sv&)>> command::handlers_sp_sv;
command::params::params() command::params::params()
: nesting_(game::native::cmd_args->nesting) : nesting_(game::native::cmd_args->nesting)
@ -112,12 +113,22 @@ void command::add_sv(const char* name, std::function<void(game::native::gentity_
} }
} }
void command::add_sp_sv(const char* name, std::function<void(game::native::sp::gentity_s*, const params_sv&)> callback)
{
const auto command = utils::string::to_lower(name);
if (handlers_sp_sv.find(command) == handlers_sp_sv.end())
{
handlers_sp_sv[command] = callback;
}
}
void command::main_handler() void command::main_handler()
{ {
params params; params params;
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
const auto got = handlers.find(command); const auto got = command::handlers.find(command);
if (got != handlers.end()) if (got != handlers.end())
{ {
@ -137,7 +148,7 @@ void command::client_command_stub(int client_num)
params_sv params; params_sv params;
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
const auto got = handlers_sv.find(command); const auto got = command::handlers_sv.find(command);
if (got != handlers_sv.end()) if (got != handlers_sv.end())
{ {
@ -148,6 +159,45 @@ void command::client_command_stub(int client_num)
game::native::ClientCommand(client_num); game::native::ClientCommand(client_num);
} }
void command::client_command_sp(int client_num, const char* s)
{
auto* entity = &game::native::sp::g_entities[client_num];
assert(entity != nullptr); // On sp it should only be an assertion
params_sv params;
const auto command = utils::string::to_lower(params[0]);
const auto got = command::handlers_sp_sv.find(command);
if (got != handlers_sp_sv.end())
{
got->second(entity, params);
}
}
__declspec(naked) void command::client_command_sp_stub()
{
__asm
{
pushad
push [esp + 0x20 + 0x8]
push [esp + 0x20 + 0x8]
call command::client_command_sp
add esp, 0x8
popad
// Code our hook skipped
mov eax, [esp + 0x8]
sub esp, 0x400
push 0x44BB5A // ClientCommand
retn
}
}
__declspec(naked) void command::client_command_dedi_stub() __declspec(naked) void command::client_command_dedi_stub()
{ {
__asm __asm
@ -163,6 +213,81 @@ __declspec(naked) void command::client_command_dedi_stub()
} }
} }
// Between ufo/noclip functions and their mp counterpart is that I reversed the 'CG' type
void command::add_sp_commands()
{
add("noclip", []()
{
const auto* ent = &game::native::sp::g_entities[0];
if (ent->health < 1)
return;
ent->client->flags ^= 1;
const auto* msg = (ent->client->flags & 1) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF";
printf("%s\n", game::native::SEH_LocalizeTextMessage(msg, "noclip print", game::native::LOCMSG_SAFE));
});
add("ufo", []()
{
const auto* ent = &game::native::sp::g_entities[0];
if (ent->health < 1)
return;
ent->client->flags ^= 2;
const auto* msg = (ent->client->flags & 2) ? "GAME_UFOON" : "GAME_UFOOFF";
printf("%s\n", game::native::SEH_LocalizeTextMessage(msg, "ufo print", game::native::LOCMSG_SAFE));
});
add("god", []()
{
auto* ent = &game::native::sp::g_entities[0];
if (ent->health < 1)
return;
assert(ent->s.eType == game::native::ET_PLAYER);
ent->flags ^= game::native::FL_GODMODE;
const auto* msg = (ent->flags & game::native::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF";
printf("%s\n", game::native::SEH_LocalizeTextMessage(msg, "god print", game::native::LOCMSG_SAFE));
});
add("demigod", []()
{
auto* ent = &game::native::sp::g_entities[0];
if (ent->health < 1)
return;
assert(ent->s.eType == game::native::ET_PLAYER);
ent->flags ^= game::native::FL_DEMI_GODMODE;
const auto* msg = (ent->flags & game::native::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF";
printf("%s\n", game::native::SEH_LocalizeTextMessage(msg, "demigod print", game::native::LOCMSG_SAFE));
});
add("notarget", []()
{
auto* ent = &game::native::sp::g_entities[0];
if (ent->health < 1)
return;
assert(ent->s.eType == game::native::ET_PLAYER);
ent->flags ^= game::native::FL_NOTARGET;
const auto* msg = (ent->flags & game::native::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF";
printf("%s\n", game::native::SEH_LocalizeTextMessage(msg, "notarget print", game::native::LOCMSG_SAFE));
});
}
void command::post_load() void command::post_load()
{ {
if (game::is_mp()) if (game::is_mp())
@ -173,6 +298,12 @@ void command::post_load()
{ {
utils::hook(0x4F96B5, &command::client_command_dedi_stub, HOOK_CALL).install()->quick(); // SV_ExecuteClientCommand utils::hook(0x4F96B5, &command::client_command_dedi_stub, HOOK_CALL).install()->quick(); // SV_ExecuteClientCommand
} }
else
{
utils::hook(0x44BB50, &command::client_command_sp_stub, HOOK_JUMP).install()->quick();
utils::hook::nop(0x44BB55, 5); // Nop skipped instructions
add_sp_commands();
}
} }
REGISTER_MODULE(command); REGISTER_MODULE(command);

View File

@ -49,6 +49,7 @@ public:
static void add(const char* name, const std::function<void()>& callback); static void add(const char* name, const std::function<void()>& callback);
static void add_sv(const char* name, std::function<void(game::native::gentity_s*, const params_sv&)> callback); static void add_sv(const char* name, std::function<void(game::native::gentity_s*, const params_sv&)> callback);
static void add_sp_sv(const char* name, std::function<void(game::native::sp::gentity_s*, const params_sv&)> callback);
void post_load() override; void post_load() override;
@ -57,11 +58,16 @@ private:
static std::unordered_map<std::string, std::function<void(const params&)>> handlers; static std::unordered_map<std::string, std::function<void(const params&)>> handlers;
static std::unordered_map<std::string, std::function<void(game::native::gentity_s*, params_sv&)>> handlers_sv; static std::unordered_map<std::string, std::function<void(game::native::gentity_s*, params_sv&)>> handlers_sv;
static std::unordered_map<std::string, std::function<void(game::native::sp::gentity_s*, params_sv&)>> handlers_sp_sv;
static void main_handler(); static void main_handler();
static void client_command_stub(int client_num); static void client_command_stub(int client_num);
static void client_command_sp(int client_num, const char* s);
static void client_command_sp_stub();
static void client_command_dedi_stub(); static void client_command_dedi_stub();
static void add_raw(const char* name, void (*callback)()); static void add_raw(const char* name, void (*callback)());
static void add_sp_commands();
}; };