Add client dev commands & more

This commit is contained in:
Diavolo 2022-04-12 14:34:51 +02:00
parent 51278faab0
commit f9c40233d1
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
19 changed files with 300 additions and 161 deletions

View File

@ -174,7 +174,7 @@ namespace Components
return;
}
if (*Game::svs_numclients <= num)
if (*Game::svs_clientCount <= num)
{
Logger::Print("Player %d is not on the server\n", num);
return;
@ -187,7 +187,7 @@ namespace Components
Bans::InsertBan({guid, client->netchan.remoteAddress.ip});
Game::SV_KickClientError(client, reason);
Game::SV_GameDropClient(num, reason.data());
}
void Bans::UnbanClient(SteamID id)

View File

@ -341,15 +341,15 @@ namespace Components
{
if (params->get(1) == "all"s)
{
count = *Game::svs_numclients;
count = *Game::svs_clientCount;
}
else
{
char* endptr;
char* end;
const auto* input = params->get(1);
count = std::strtoul(input, &endptr, 10);
count = std::strtoul(input, &end, 10);
if (input == endptr)
if (input == end)
{
Logger::Print("Warning: %s is not a valid input\n"
"Usage: %s optional <number of bots> or optional <\"all\">\n",
@ -359,7 +359,7 @@ namespace Components
}
}
count = std::min(static_cast<unsigned int>(*Game::svs_numclients), count);
count = std::min(static_cast<unsigned int>(*Game::svs_clientCount), count);
// Check if ingame and host
if (!Game::SV_Loaded())

View File

@ -2,7 +2,7 @@
namespace Components
{
std::unordered_map<std::string, Utils::Slot<ClientCommand::Callback>> ClientCommand::FunctionMap;
std::unordered_map<std::string, std::function<void(Game::gentity_s*, Command::ServerParams*)>> ClientCommand::HandlersSV;
bool ClientCommand::CheatsOk(const Game::gentity_s* ent)
{
@ -25,50 +25,38 @@ namespace Components
return true;
}
bool ClientCommand::CallbackHandler(Game::gentity_s* ent, const char* cmd)
{
const auto command = Utils::String::ToLower(cmd);
const auto got = ClientCommand::FunctionMap.find(command);
if (got != ClientCommand::FunctionMap.end())
{
got->second(ent);
return true;
}
return false;
}
void ClientCommand::Add(const char* name, Utils::Slot<Callback> callback)
void ClientCommand::Add(const char* name, std::function<void(Game::gentity_s*, Command::ServerParams*)> callback)
{
const auto command = Utils::String::ToLower(name);
ClientCommand::FunctionMap[command] = std::move(callback);
ClientCommand::HandlersSV[command] = std::move(callback);
}
void ClientCommand::ClientCommandStub(const int clientNum)
{
char cmd[1024]{};
const auto entity = &Game::g_entities[clientNum];
const auto ent = &Game::g_entities[clientNum];
if (entity->client == nullptr)
if (ent->client == nullptr)
{
Logger::Print("ClientCommand: client %d is not fully in game yet\n", clientNum);
return;
}
Game::SV_Cmd_ArgvBuffer(0, cmd, sizeof(cmd));
Command::ServerParams params;
const auto command = Utils::String::ToLower(params.get(0));
if (!ClientCommand::CallbackHandler(entity, cmd))
if (const auto got = HandlersSV.find(command); got != HandlersSV.end())
{
// If no callback was found call original game function
Utils::Hook::Call<void(const int)>(0x416790)(clientNum);
got->second(ent, &params);
return;
}
Utils::Hook::Call<void(const int)>(0x416790)(clientNum);
}
void ClientCommand::AddCheatCommands()
{
ClientCommand::Add("noclip", [](Game::gentity_s* ent)
ClientCommand::Add("noclip", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
@ -82,7 +70,7 @@ namespace Components
(ent->client->flags & Game::PLAYER_FLAG_NOCLIP) ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF"));
});
ClientCommand::Add("ufo", [](Game::gentity_s* ent)
ClientCommand::Add("ufo", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
@ -96,7 +84,7 @@ namespace Components
(ent->client->flags & Game::PLAYER_FLAG_UFO) ? "GAME_UFOON" : "GAME_UFOOFF"));
});
ClientCommand::Add("god", [](Game::gentity_s* ent)
ClientCommand::Add("god", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
@ -110,7 +98,7 @@ namespace Components
(ent->flags & Game::FL_GODMODE) ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF"));
});
ClientCommand::Add("demigod", [](Game::gentity_s* ent)
ClientCommand::Add("demigod", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
@ -124,7 +112,7 @@ namespace Components
(ent->flags & Game::FL_DEMI_GODMODE) ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF"));
});
ClientCommand::Add("notarget", [](Game::gentity_s* ent)
ClientCommand::Add("notarget", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (!ClientCommand::CheatsOk(ent))
return;
@ -138,17 +126,16 @@ namespace Components
(ent->flags & Game::FL_NOTARGET) ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF"));
});
ClientCommand::Add("setviewpos", [](Game::gentity_s* ent)
ClientCommand::Add("setviewpos", [](Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
assert(ent != nullptr);
if (!ClientCommand::CheatsOk(ent))
return;
Command::ServerParams params = {};
Game::vec3_t origin, angles{0.f, 0.f, 0.f};
if (params.size() < 4 || params.size() > 6)
if (params->size() < 4 || params->size() > 6)
{
Game::SV_GameSendServerCommand(ent->s.number, 0,
Utils::String::VA("%c \"GAME_USAGE\x15: setviewpos x y z [yaw] [pitch]\n\"", 0x65));
@ -157,23 +144,109 @@ namespace Components
for (auto i = 0; i < 3; i++)
{
origin[i] = std::strtof(params.get(i + 1), nullptr);
origin[i] = std::strtof(params->get(i + 1), nullptr);
}
if (params.size() >= 5)
if (params->size() >= 5)
{
angles[1] = std::strtof(params.get(4), nullptr); // Yaw
angles[1] = std::strtof(params->get(4), nullptr); // Yaw
}
if (params.size() == 6)
if (params->size() == 6)
{
angles[0] = std::strtof(params.get(5), nullptr); // Pitch
angles[0] = std::strtof(params->get(5), nullptr); // Pitch
}
Game::TeleportPlayer(ent, origin, angles);
});
}
void ClientCommand::AddDevelopmentCommands()
{
ClientCommand::Add("dropallbots", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
Game::SV_DropAllBots();
});
ClientCommand::Add("entitylist", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
Game::Svcmd_EntityList_f();
});
ClientCommand::Add("printentities", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
Game::G_PrintEntities();
});
ClientCommand::Add("entitycount", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
Logger::Print("Entity count = %i\n", *Game::level_num_entities);
});
// Also known as: "vis"
ClientCommand::Add("visionsetnaked", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (params->size() < 2)
{
Logger::Print("USAGE: visionSetNaked <name> <duration>\n");
return;
}
auto duration = 1000;
if (params->size() > 2)
{
const auto input = std::strtof(params->get(2), nullptr);
duration = static_cast<int>(std::floorf(input * 1000.0f + 0.5f));
}
assert(ent->client != nullptr);
constexpr auto visMode = Game::visionSetMode_t::VISIONSET_NORMAL;
const auto* name = params->get(1);
ent->client->visionDuration[visMode] = duration;
strncpy_s(ent->client->visionName[visMode],
sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE);
Game::SV_GameSendServerCommand(ent->s.number, 1,
Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration));
});
ClientCommand::Add("visionsetnight", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
if (params->size() < 2)
{
Logger::Print("USAGE: visionSetNight <name> <duration>\n");
return;
}
auto duration = 1000;
if (params->size() > 2)
{
const auto input = std::strtof(params->get(2), nullptr);
duration = static_cast<int>(std::floorf(input * 1000.0f + 0.5f));
}
assert(ent->client != nullptr);
constexpr auto visMode = Game::visionSetMode_t::VISIONSET_NIGHT;
const auto* name = params->get(1);
ent->client->visionDuration[visMode] = duration;
strncpy_s(ent->client->visionName[visMode],
sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE);
Game::SV_GameSendServerCommand(ent->s.number, 1,
Utils::String::VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration));
});
ClientCommand::Add("g_testCmd", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params)
{
assert(ent != nullptr);
ent->client->ps.stunTime = 1000 + *Game::level_time; // 1000 is the default test stun time
});
}
void ClientCommand::AddScriptFunctions()
{
Script::AddMethod("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(<optional int toggle>);
@ -280,6 +353,11 @@ namespace Components
ent->flags ^= Game::FL_NOTARGET;
}
});
Script::AddFunction("DropAllBots", []() // gsc: DropAllBots();
{
Game::SV_DropAllBots();
});
}
ClientCommand::ClientCommand()
@ -289,5 +367,8 @@ namespace Components
ClientCommand::AddCheatCommands();
ClientCommand::AddScriptFunctions();
#ifdef _DEBUG
ClientCommand::AddDevelopmentCommands();
#endif
}
}

View File

@ -5,19 +5,17 @@ namespace Components
class ClientCommand : public Component
{
public:
typedef void(Callback)(Game::gentity_s* entity);
ClientCommand();
static void Add(const char* name, Utils::Slot<Callback> callback);
static void Add(const char* name, std::function<void(Game::gentity_s*, Command::ServerParams*)> callback);
static bool CheatsOk(const Game::gentity_s* ent);
private:
static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMap;
static std::unordered_map<std::string, std::function<void(Game::gentity_s*, Command::ServerParams*)>> HandlersSV;
static bool CallbackHandler(Game::gentity_s* ent, const char* cmd);
static void ClientCommandStub(const int clientNum);
static void AddCheatCommands();
static void AddDevelopmentCommands();
static void AddScriptFunctions();
};
}

View File

@ -2,8 +2,8 @@
namespace Components
{
std::unordered_map<std::string, Utils::Slot<Command::Callback>> Command::FunctionMap;
std::unordered_map<std::string, Utils::Slot<Command::Callback>> Command::FunctionMapSV;
std::unordered_map<std::string, std::function<void(Command::Params*)>> Command::FunctionMap;
std::unordered_map<std::string, std::function<void(Command::Params*)>> Command::FunctionMapSV;
std::string Command::Params::join(const int index)
{
@ -60,7 +60,7 @@ namespace Components
return Game::sv_cmd_args->argv[this->nesting_][index];
}
void Command::Add(const char* name, Utils::Slot<Command::Callback> callback)
void Command::Add(const char* name, std::function<void(Command::Params*)> callback)
{
const auto command = Utils::String::ToLower(name);
@ -69,10 +69,10 @@ namespace Components
Command::AddRaw(name, Command::MainCallback);
}
Command::FunctionMap[command] = std::move(callback);
Command::FunctionMap.insert_or_assign(command, std::move(callback));
}
void Command::AddSV(const char* name, Utils::Slot<Command::Callback> callback)
void Command::AddSV(const char* name, std::function<void(Command::Params*)> callback)
{
if (Loader::IsPregame())
{
@ -95,7 +95,7 @@ namespace Components
Command::AddRaw(name, Game::Cbuf_AddServerText);
}
FunctionMapSV[command] = std::move(callback);
FunctionMapSV.insert_or_assign(command, std::move(callback));
}
void Command::AddRaw(const char* name, void(*callback)(), bool key)
@ -127,11 +127,11 @@ namespace Components
Game::cmd_function_t* Command::Find(const std::string& command)
{
Game::cmd_function_t* cmdFunction = *Game::cmd_functions;
auto* cmdFunction = *Game::cmd_functions;
while (cmdFunction)
while (cmdFunction != nullptr)
{
if (cmdFunction->name && cmdFunction->name == command)
if (cmdFunction->name != nullptr && cmdFunction->name == command)
{
return cmdFunction;
}
@ -149,12 +149,10 @@ namespace Components
void Command::MainCallback()
{
Command::ClientParams params;
ClientParams params;
const auto command = Utils::String::ToLower(params[0]);
const auto got = Command::FunctionMap.find(command);
if (got != Command::FunctionMap.end())
if (const auto got = FunctionMap.find(command); got != FunctionMap.end())
{
got->second(&params);
}
@ -162,12 +160,10 @@ namespace Components
void Command::MainCallbackSV()
{
Command::ServerParams params;
ServerParams params;
const auto command = Utils::String::ToLower(params[0]);
const auto got = Command::FunctionMapSV.find(command);
if (got != Command::FunctionMapSV.end())
if (const auto got = FunctionMapSV.find(command); got != FunctionMapSV.end())
{
got->second(&params);
}

View File

@ -8,7 +8,8 @@ namespace Components
class Params
{
public:
Params() {};
Params() = default;
virtual ~Params() = default;
virtual int size() = 0;
virtual const char* get(int index) = 0;
@ -20,7 +21,7 @@ namespace Components
}
};
class ClientParams : public Params
class ClientParams final : public Params
{
public:
ClientParams();
@ -32,7 +33,7 @@ namespace Components
int nesting_;
};
class ServerParams : public Params
class ServerParams final : public Params
{
public:
ServerParams();
@ -44,14 +45,12 @@ namespace Components
int nesting_;
};
typedef void(Callback)(Command::Params* params);
Command();
static Game::cmd_function_t* Allocate();
static void Add(const char* name, Utils::Slot<Callback> callback);
static void AddSV(const char* name, Utils::Slot<Callback> callback);
static void Add(const char* name, std::function<void(Command::Params*)> callback);
static void AddSV(const char* name, std::function<void(Command::Params*)> callback);
static void AddRaw(const char* name, void(*callback)(), bool key = false);
static void AddRawSV(const char* name, void(*callback)());
static void Execute(std::string command, bool sync = true);
@ -59,8 +58,8 @@ namespace Components
static Game::cmd_function_t* Find(const std::string& command);
private:
static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMap;
static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMapSV;
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMap;
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMapSV;
static void MainCallback();
static void MainCallbackSV();

View File

@ -51,8 +51,8 @@ namespace Components
{
SetConsoleTitleA(hostname.data());
int clientCount = 0;
int maxclientCount = *Game::svs_numclients;
auto clientCount = 0;
auto maxclientCount = *Game::svs_clientCount;
if (maxclientCount)
{

View File

@ -381,7 +381,7 @@ namespace Components
{
Network::Address address(nc->sa.sa);
for (int i = 0; i < *Game::svs_numclients; ++i)
for (int i = 0; i < *Game::svs_clientCount; ++i)
{
Game::client_t* client = &Game::svs_clients[i];

View File

@ -307,7 +307,7 @@ namespace Components
{
int botCount = 0;
int clientCount = 0;
int maxclientCount = *Game::svs_numclients;
int maxclientCount = *Game::svs_clientCount;
if (maxclientCount)
{

View File

@ -18,16 +18,16 @@ namespace Components
void Script::FunctionError()
{
std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
const auto* funcName = Game::SL_ConvertToString(Script::FunctionName);
Game::Scr_ShutdownAllocNode();
Logger::Print(23, "\n");
Logger::Print(23, "******* script compile error *******\n");
Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data());
Logger::Print(23, "Error: unknown function %s in %s\n", funcName, Script::ScriptName.data());
Logger::Print(23, "************************************\n");
Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data());
Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\nunknown function %s\n%s\n\n", funcName, Script::ScriptName.data());
}
__declspec(naked) void Script::StoreFunctionNameStub()
@ -270,27 +270,27 @@ namespace Components
Game::GScr_LoadGameTypeScript();
}
void Script::AddFunction(const char* name, Game::xfunction_t func, int type)
void Script::AddFunction(const char* name, Game::BuiltinFunction func, int type)
{
Game::BuiltinFunctionDef toAdd;
toAdd.actionString = name;
toAdd.actionFunc = func;
toAdd.type = type;
CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd));
CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), toAdd);
}
void Script::AddMethod(const char* name, Game::xmethod_t func, int type)
void Script::AddMethod(const char* name, Game::BuiltinMethod func, int type)
{
Game::BuiltinMethodDef toAdd;
toAdd.actionString = name;
toAdd.actionFunc = func;
toAdd.type = type;
CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd));
CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), toAdd);
}
Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type)
Game::BuiltinFunction Script::BuiltIn_GetFunctionStub(const char** pName, int* type)
{
if (pName != nullptr)
{
@ -311,10 +311,10 @@ namespace Components
}
}
return Utils::Hook::Call<Game::xfunction_t(const char**, int*)>(0x5FA2B0)(pName, type); // BuiltIn_GetFunction
return Utils::Hook::Call<Game::BuiltinFunction(const char**, int*)>(0x5FA2B0)(pName, type); // BuiltIn_GetFunction
}
Game::xmethod_t Script::BuiltIn_GetMethod(const char** pName, int* type)
Game::BuiltinMethod Script::BuiltIn_GetMethod(const char** pName, int* type)
{
if (pName != nullptr)
{
@ -335,7 +335,7 @@ namespace Components
}
}
return Utils::Hook::Call<Game::xmethod_t(const char**, int*)>(0x5FA360)(pName, type); // Player_GetMethod
return Utils::Hook::Call<Game::BuiltinMethod(const char**, int*)>(0x5FA360)(pName, type); // Player_GetMethod
}
void Script::StoreScriptBaseProgramNum()
@ -538,7 +538,7 @@ namespace Components
return nullptr;
}
if (ent->s.number >= *Game::svs_numclients)
if (ent->s.number >= *Game::svs_clientCount)
{
Game::Scr_ObjectError(Utils::String::VA("Entity %i is out of bounds", ent->s.number));
return nullptr;

View File

@ -11,8 +11,8 @@ namespace Components
static int LoadScriptAndLabel(const std::string& script, const std::string& label);
static void AddFunction(const char* name, Game::xfunction_t func, int type = 0);
static void AddMethod(const char* name, Game::xmethod_t func, int type = 0);
static void AddFunction(const char* name, Game::BuiltinFunction func, int type = 0);
static void AddMethod(const char* name, Game::BuiltinMethod func, int type = 0);
static void OnVMShutdown(Utils::Slot<Scheduler::Callback> callback);
@ -49,8 +49,8 @@ namespace Components
static void LoadGameType();
static void LoadGameTypeScript();
static Game::xfunction_t BuiltIn_GetFunctionStub(const char** pName, int* type);
static Game::xmethod_t BuiltIn_GetMethod(const char** pName, int* type);
static Game::BuiltinFunction BuiltIn_GetFunctionStub(const char** pName, int* type);
static Game::BuiltinMethod BuiltIn_GetMethod(const char** pName, int* type);
static void ScrShutdownSystemStub(unsigned char sys);
static void StoreScriptBaseProgramNumStub();

View File

@ -2,24 +2,24 @@
namespace Components
{
std::unordered_map<std::int32_t, Utils::Slot<bool(Command::Params*)>> ServerCommands::Commands;
std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> ServerCommands::Commands;
void ServerCommands::OnCommand(std::int32_t cmd, Utils::Slot<bool(Command::Params*)> cb)
void ServerCommands::OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> callback)
{
ServerCommands::Commands[cmd] = cb;
ServerCommands::Commands.insert_or_assign(cmd, std::move(callback));
}
bool ServerCommands::OnServerCommand()
{
Command::ClientParams params;
for (const auto& serverCommandCB : ServerCommands::Commands)
for (const auto& [id, callback] : ServerCommands::Commands)
{
if (params.size() >= 1)
{
if (params.get(0)[0] == serverCommandCB.first)
if (params.get(0)[0] == id) // Compare ID of server command
{
return serverCommandCB.second(&params);
return callback(&params);
}
}
}
@ -27,7 +27,7 @@ namespace Components
return false;
}
__declspec(naked) void ServerCommands::OnServerCommandStub()
__declspec(naked) void ServerCommands::CG_DeployServerCommand_Stub()
{
__asm
{
@ -44,7 +44,7 @@ namespace Components
test eax, eax
jle error
mov eax, DWORD PTR[edx * 4 + 1AAC634h]
mov eax, dword ptr [edx * 4 + 1AAC634h]
mov eax, [eax]
push 5944B3h
@ -63,6 +63,6 @@ namespace Components
ServerCommands::ServerCommands()
{
// Server command receive hook
Utils::Hook(0x59449F, ServerCommands::OnServerCommandStub).install()->quick();
Utils::Hook(0x59449F, ServerCommands::CG_DeployServerCommand_Stub).install()->quick();
}
}

View File

@ -7,12 +7,12 @@ namespace Components
public:
ServerCommands();
static void OnCommand(std::int32_t cmd, Utils::Slot<bool(Command::Params*)> cb);
static void OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> callback);
private:
static std::unordered_map<std::int32_t, Utils::Slot<bool(Command::Params*)>> Commands;
static std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> Commands;
static bool OnServerCommand();
static void OnServerCommandStub();
static void CG_DeployServerCommand_Stub();
};
}

View File

@ -125,7 +125,7 @@ namespace Components
Utils::InfoString ServerInfo::GetInfo()
{
int maxclientCount = *Game::svs_numclients;
int maxclientCount = *Game::svs_clientCount;
if (!maxclientCount)
{

View File

@ -68,7 +68,7 @@ namespace Components
SlowMotion::Delay = delay;
// set snapshot num to 1 behind (T6 does this, why shouldn't we?)
for (int i = 0; i < *Game::svs_numclients; ++i)
for (int i = 0; i < *Game::svs_clientCount; ++i)
{
Game::svs_clients[i].snapNum = *reinterpret_cast<DWORD*>(0x31D9384) - 1;
}

View File

@ -41,7 +41,17 @@ namespace Components
if (params.size() <= 1)
return 0;
int index = atoi(params[1]);
char* end;
const auto* input = params.get(1);
auto index = std::strtol(input, &end, 10);
if (input == end)
{
Logger::Print("Warning: %s is not a valid input\n"
"Usage: %s <weapon index>\n",
input, params.get(0));
return 0;
}
if (index >= 4139)
{
@ -56,7 +66,7 @@ namespace Components
return 0;
}
Utils::Hook::Call<void(int, int)>(0x4BD520)(0, index);
Game::CG_SetupWeaponDef(0, index);
return 1;
}

View File

@ -5,19 +5,19 @@ namespace Game
std::vector<std::string> Sys_ListFilesWrapper(const std::string& directory, const std::string& extension)
{
auto fileCount = 0;
auto files = Game::Sys_ListFiles(directory.data(), extension.data(), 0, &fileCount, 0);
auto** const files = Sys_ListFiles(directory.data(), extension.data(), nullptr, &fileCount, 0);
std::vector<std::string> result;
for (auto i = 0; i < fileCount; i++)
{
if (files[i])
if (files[i] != nullptr)
{
result.push_back(files[i]);
result.emplace_back(files[i]);
}
}
Game::FS_FreeFileList(files);
FS_FreeFileList(files);
return result;
}
@ -31,6 +31,7 @@ namespace Game
BG_GetWeaponName_t BG_GetWeaponName = BG_GetWeaponName_t(0x4E6EC0);
BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = BG_LoadWeaponDef_LoadObj_t(0x57B5F0);
BG_GetWeaponDef_t BG_GetWeaponDef = BG_GetWeaponDef_t(0x440EB0);
BG_GetEntityTypeName_t BG_GetEntityTypeName = BG_GetEntityTypeName_t(0x43A0E0);
Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0);
Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20);
@ -44,6 +45,8 @@ namespace Game
CG_ScoresUp_f_t CG_ScoresUp_f = CG_ScoresUp_f_t(0x5802C0);
CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp = CG_ScrollScoreboardUp_t(0x47A5C0);
CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown = CG_ScrollScoreboardDown_t(0x493B50);
CG_GetTeamName_t CG_GetTeamName = CG_GetTeamName_t(0x4B6210);
CG_SetupWeaponDef_t CG_SetupWeaponDef = CG_SetupWeaponDef_t(0x4BD520);
CL_GetClientName_t CL_GetClientName = CL_GetClientName_t(0x4563D0);
CL_IsCgameInitialized_t CL_IsCgameInitialized = CL_IsCgameInitialized_t(0x43EB20);
@ -152,6 +155,10 @@ namespace Game
G_GetWeaponIndexForName_t G_GetWeaponIndexForName = G_GetWeaponIndexForName_t(0x49E540);
G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString = G_SpawnEntitiesFromString_t(0x4D8840);
G_PrintEntities_t G_PrintEntities = G_PrintEntities_t(0x4E6A50);
G_GetEntityTypeName_t G_GetEntityTypeName = G_GetEntityTypeName_t(0x4EB810);
Svcmd_EntityList_f_t Svcmd_EntityList_f = Svcmd_EntityList_f_t(0x4B6A70);
GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript = GScr_LoadGameTypeScript_t(0x4ED9A0);
@ -339,6 +346,7 @@ namespace Game
SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0);
SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0);
SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0);
SV_DropClient_t SV_DropClient = SV_DropClient_t(0x4D1600);
SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0);
SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390);
@ -421,7 +429,7 @@ namespace Game
float* cgameFOVSensitivityScale = reinterpret_cast<float*>(0xB2F884);
int* svs_time = reinterpret_cast<int*>(0x31D9384);
int* svs_numclients = reinterpret_cast<int*>(0x31D938C);
int* svs_clientCount = reinterpret_cast<int*>(0x31D938C);
client_t* svs_clients = reinterpret_cast<client_t*>(0x31D9390);
UiContext *uiContext = reinterpret_cast<UiContext *>(0x62E2858);
@ -452,6 +460,8 @@ namespace Game
gentity_t* g_entities = reinterpret_cast<gentity_t*>(0x18835D8);
int* level_num_entities = reinterpret_cast<int*>(0x1A831B0);
int* level_time = reinterpret_cast<int*>(0x1A83554);
int* level_scriptPrintChannel = reinterpret_cast<int*>(0x1A860FC);
netadr_t* connectedHost = reinterpret_cast<netadr_t*>(0xA1E888);
@ -520,6 +530,10 @@ namespace Game
GraphFloat* aaInputGraph = reinterpret_cast<GraphFloat*>(0x7A2FC0);
const char* MY_CMDS = reinterpret_cast<const char*>(0x73C9C4); // Count 5
XModel** cached_models = reinterpret_cast<XModel**>(0x1AA20C8);
FastCriticalSection* db_hashCritSect = reinterpret_cast<FastCriticalSection*>(0x16B8A54);
vec3_t* CorrectSolidDeltas = reinterpret_cast<vec3_t*>(0x739BB8); // Count 26
@ -536,6 +550,13 @@ namespace Game
InterlockedDecrement(&critSect->readCount);
}
XModel* G_GetModel(const int index)
{
assert(index > 0);
assert(index < MAX_MODELS);
return cached_models[index];
}
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize)
{
int elSize = DB_GetXAssetSizeHandlers[type]();
@ -722,14 +743,27 @@ namespace Game
return hash;
}
void SV_KickClientError(client_t* client, const std::string& reason)
void SV_GameDropClient(int clientNum, const char* reason)
{
if (client->state < 5)
const auto maxClients = Dvar_FindVar("sv_maxclients")->current.integer;
assert(maxClients >= 1 && maxClients <= 18);
if (clientNum >= 0 && clientNum < maxClients)
{
Components::Network::SendCommand(client->netchan.remoteAddress, "error", reason);
SV_DropClient(&svs_clients[clientNum], reason, true);
}
}
SV_KickClient(client, reason.data());
void SV_DropAllBots()
{
for (auto i = 0; i < *svs_clientCount; ++i)
{
if (svs_clients[i].state != clientstate_t::CS_FREE
&& svs_clients[i].netchan.remoteAddress.type == netadrtype_t::NA_BOT)
{
SV_GameDropClient(i, "GAME_GET_TO_COVER");
}
}
}
void IncInParam()
@ -1199,28 +1233,6 @@ namespace Game
}
}
__declspec(naked) void SV_KickClient(client_t* /*client*/, const char* /*reason*/)
{
__asm
{
pushad
mov edi, 0
mov esi, [esp + 24h]
push [esp + 28h]
push 0
push 0
mov eax, 6249A0h
call eax
add esp, 0Ch
popad
retn
}
}
__declspec(naked) void Scr_NotifyId(unsigned int /*id*/, unsigned __int16 /*stringValue*/, unsigned int /*paramcount*/)
{
__asm

View File

@ -43,6 +43,9 @@ namespace Game
typedef WeaponDef* (__cdecl * BG_GetWeaponDef_t)(int weaponIndex);
extern BG_GetWeaponDef_t BG_GetWeaponDef;
typedef const char*(__cdecl * BG_GetEntityTypeName_t)(const int eType);
extern BG_GetEntityTypeName_t BG_GetEntityTypeName;
typedef void(__cdecl * Cbuf_AddServerText_t)();
extern Cbuf_AddServerText_t Cbuf_AddServerText;
@ -76,6 +79,12 @@ namespace Game
typedef void(__cdecl * CG_ScrollScoreboardDown_t)(cg_s* cgameGlob);
extern CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown;
typedef const char*(__cdecl * CG_GetTeamName_t)(team_t team);
extern CG_GetTeamName_t CG_GetTeamName;
typedef void(__cdecl * CG_SetupWeaponDef_t)(int localClientNum, unsigned int weapIndex);
extern CG_SetupWeaponDef_t CG_SetupWeaponDef;
typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size);
extern CL_GetClientName_t CL_GetClientName;
@ -377,6 +386,15 @@ namespace Game
typedef void(__cdecl * G_SpawnEntitiesFromString_t)();
extern G_SpawnEntitiesFromString_t G_SpawnEntitiesFromString;
typedef void(__cdecl * G_PrintEntities_t)();
extern G_PrintEntities_t G_PrintEntities;
typedef const char*(__cdecl * G_GetEntityTypeName_t)(const gentity_s* ent);
extern G_GetEntityTypeName_t G_GetEntityTypeName;
typedef void(__cdecl * Svcmd_EntityList_f_t)();
extern Svcmd_EntityList_f_t Svcmd_EntityList_f;
typedef void(__cdecl * GScr_LoadGameTypeScript_t)();
extern GScr_LoadGameTypeScript_t GScr_LoadGameTypeScript;
@ -750,7 +768,7 @@ namespace Game
typedef unsigned int(__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation);
extern SEH_ReadCharFromString_t SEH_ReadCharFromString;
typedef char*(__cdecl * SL_ConvertToString_t)(unsigned short stringValue);
typedef const char*(__cdecl * SL_ConvertToString_t)(scr_string_t stringValue);
extern SL_ConvertToString_t SL_ConvertToString;
typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user);
@ -816,6 +834,9 @@ namespace Game
typedef void(__cdecl * SV_ClientThink_t)(client_s*, usercmd_s*);
extern SV_ClientThink_t SV_ClientThink;
typedef void(__cdecl * SV_DropClient_t)(client_t* drop, const char* reason, bool tellThem);
extern SV_DropClient_t SV_DropClient;
typedef client_t*(__cdecl * SV_GetPlayerByName_t)();
extern SV_GetPlayerByName_t SV_GetPlayerByName;
@ -979,7 +1000,7 @@ namespace Game
extern float* cgameFOVSensitivityScale;
extern int* svs_time;
extern int* svs_numclients;
extern int* svs_clientCount;
extern client_t* svs_clients;
extern source_t **sourceFiles;
@ -1015,6 +1036,8 @@ namespace Game
constexpr auto ENTITYNUM_NONE = MAX_GENTITIES - 1;
extern gentity_t* g_entities;
extern int* level_num_entities;
extern int* level_time;
extern int* level_scriptPrintChannel;
extern netadr_t* connectedHost;
@ -1085,6 +1108,11 @@ namespace Game
constexpr auto AIM_ASSIST_GRAPH_COUNT = 4u;
extern GraphFloat* aaInputGraph;
extern const char* MY_CMDS;
constexpr auto MAX_MODELS = 512;
extern XModel** cached_models;
extern vec3_t* CorrectSolidDeltas;
extern FastCriticalSection* db_hashCritSect;
@ -1092,6 +1120,8 @@ namespace Game
void Sys_LockRead(FastCriticalSection* critSect);
void Sys_UnlockRead(FastCriticalSection* critSect);
XModel* G_GetModel(int index);
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
void Menu_FreeItemMemory(Game::itemDef_s* item);
void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1);
@ -1120,8 +1150,8 @@ namespace Game
void R_LoadSunThroughDvars(const char* mapname, sunflare_t* sun);
void R_SetSunFromDvars(sunflare_t* sun);
void SV_KickClient(client_t* client, const char* reason);
void SV_KickClientError(client_t* client, const std::string& reason);
void SV_GameDropClient(int clientNum, const char* reason);
void SV_DropAllBots();
void SV_BotUserMove(client_t* client);
void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg);

View File

@ -28,20 +28,20 @@ namespace Game
unsigned __int16 classnum;
};
typedef void(__cdecl * xfunction_t)();
typedef void(__cdecl * xmethod_t)(scr_entref_t);
typedef void(__cdecl * BuiltinFunction)();
typedef void(__cdecl * BuiltinMethod)(scr_entref_t);
struct BuiltinFunctionDef
{
const char* actionString;
xfunction_t actionFunc;
BuiltinFunction actionFunc;
int type;
};
struct BuiltinMethodDef
{
const char* actionString;
xmethod_t actionFunc;
BuiltinMethod actionFunc;
int type;
};
@ -5576,15 +5576,25 @@ namespace Game
CON_CONNECTED = 0x2
} clientConnected_t;
typedef enum
{
VISIONSET_NORMAL,
VISIONSET_NIGHT,
VISIONSET_MISSILECAM,
VISIONSET_THERMAL,
VISIONSET_PAIN,
VISIONSETCOUNT
} visionSetMode_t;
typedef struct gclient_s
{
playerState_s ps;
sessionState_t sessionState; // 12572
char pad0[40];
unsigned char __pad0[40];
clientConnected_t connected; // 12616
char pad1[144];
unsigned int team; // 12764
char pad2[436];
unsigned char __pad1[144];
team_t team; // 12764
unsigned char __pad2[436];
int flags; // 13204
int spectatorClient;
int lastCmdTime;
@ -5592,7 +5602,10 @@ namespace Game
int oldbuttons; // 13220
int latched_buttons; // 13224
int buttonsSinceLastFrame; // 13228
char pad3[700]; // 13232
unsigned char __pad3[324]; // 13232
int visionDuration[5];
char visionName[5][64];
unsigned char __pad4[36];
} gclient_t;
static_assert(sizeof(gclient_t) == 13932);