Feature/set get stat (#485)
* [Script]: GetStat & SetStat from CoD4(x) * [Stats] Remove limitation * [Bullet] Clean this up
This commit is contained in:
parent
be1bc5fd10
commit
e49194ff65
@ -20,7 +20,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Game's code
|
// Game's code
|
||||||
if (surfaceType != Game::materialSurfType_t::SURF_TYPE_DEFAULT)
|
if (surfaceType != Game::SURF_TYPE_DEFAULT)
|
||||||
{
|
{
|
||||||
return (*Game::penetrationDepthTable)[weapDef->penetrateType][surfaceType];
|
return (*Game::penetrationDepthTable)[weapDef->penetrateType][surfaceType];
|
||||||
}
|
}
|
||||||
|
@ -272,18 +272,5 @@ namespace Components
|
|||||||
// clanName in CG_Obituary
|
// clanName in CG_Obituary
|
||||||
Utils::Hook(0x586DD6, PlayerName::GetClientName, HOOK_CALL).install()->quick();
|
Utils::Hook(0x586DD6, PlayerName::GetClientName, HOOK_CALL).install()->quick();
|
||||||
Utils::Hook(0x586E2A, PlayerName::GetClientName, HOOK_CALL).install()->quick();
|
Utils::Hook(0x586E2A, PlayerName::GetClientName, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
Command::Add("statGet", [](Command::Params* params)
|
|
||||||
{
|
|
||||||
if (params->size() < 2)
|
|
||||||
{
|
|
||||||
Logger::PrintError(Game::CON_CHANNEL_SERVER, "statget usage: statget <index>\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto index = std::atoi(params->get(1));
|
|
||||||
const auto stat = Game::LiveStorage_GetStat(0, index);
|
|
||||||
Logger::Print(Game::CON_CHANNEL_SYSTEM, "Stat {}: {}\n", index, stat);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ namespace Components
|
|||||||
void ScriptExtension::AddMethods()
|
void ScriptExtension::AddMethods()
|
||||||
{
|
{
|
||||||
// ScriptExtension methods
|
// ScriptExtension methods
|
||||||
Script::AddMethod("GetIp", [](Game::scr_entref_t entref) // gsc: self GetIp()
|
Script::AddMethod("GetIp", [](const Game::scr_entref_t entref) // gsc: self GetIp()
|
||||||
{
|
{
|
||||||
const auto* ent = Game::GetPlayerEntity(entref);
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
const auto* client = Script::GetClient(ent);
|
const auto* client = Script::GetClient(ent);
|
||||||
@ -259,7 +259,7 @@ namespace Components
|
|||||||
Game::Scr_AddString(ip.data());
|
Game::Scr_AddString(ip.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
Script::AddMethod("GetPing", [](Game::scr_entref_t entref) // gsc: self GetPing()
|
Script::AddMethod("GetPing", [](const Game::scr_entref_t entref) // gsc: self GetPing()
|
||||||
{
|
{
|
||||||
const auto* ent = Game::GetPlayerEntity(entref);
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
const auto* client = Script::GetClient(ent);
|
const auto* client = Script::GetClient(ent);
|
||||||
@ -267,7 +267,7 @@ namespace Components
|
|||||||
Game::Scr_AddInt(client->ping);
|
Game::Scr_AddInt(client->ping);
|
||||||
});
|
});
|
||||||
|
|
||||||
Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing(<int>)
|
Script::AddMethod("SetPing", [](const Game::scr_entref_t entref) // gsc: self SetPing(<int>)
|
||||||
{
|
{
|
||||||
auto ping = Game::Scr_GetInt(0);
|
auto ping = Game::Scr_GetInt(0);
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ namespace Components
|
|||||||
|
|
||||||
void ScriptExtension::AddEntityFields()
|
void ScriptExtension::AddEntityFields()
|
||||||
{
|
{
|
||||||
AddEntityField("entityflags", Game::fieldtype_t::F_INT,
|
AddEntityField("entityflags", Game::F_INT,
|
||||||
[](Game::gentity_s* ent, [[maybe_unused]] int offset)
|
[](Game::gentity_s* ent, [[maybe_unused]] int offset)
|
||||||
{
|
{
|
||||||
ent->flags = Game::Scr_GetInt(0);
|
ent->flags = Game::Scr_GetInt(0);
|
||||||
@ -319,7 +319,7 @@ namespace Components
|
|||||||
|
|
||||||
void ScriptExtension::AddClientFields()
|
void ScriptExtension::AddClientFields()
|
||||||
{
|
{
|
||||||
AddClientField("clientflags", Game::fieldtype_t::F_INT,
|
AddClientField("clientflags", Game::F_INT,
|
||||||
[](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField)
|
[](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField)
|
||||||
{
|
{
|
||||||
pSelf->flags = Game::Scr_GetInt(0);
|
pSelf->flags = Game::Scr_GetInt(0);
|
||||||
|
@ -2,18 +2,18 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> ServerCommands::Commands;
|
std::unordered_map<std::int32_t, ServerCommands::serverCommandHandler> ServerCommands::Commands;
|
||||||
|
|
||||||
void ServerCommands::OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> callback)
|
void ServerCommands::OnCommand(std::int32_t cmd, const serverCommandHandler& callback)
|
||||||
{
|
{
|
||||||
ServerCommands::Commands.insert_or_assign(cmd, std::move(callback));
|
Commands.insert_or_assign(cmd, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerCommands::OnServerCommand()
|
bool ServerCommands::OnServerCommand()
|
||||||
{
|
{
|
||||||
Command::ClientParams params;
|
Command::ClientParams params;
|
||||||
|
|
||||||
for (const auto& [id, callback] : ServerCommands::Commands)
|
for (const auto& [id, callback] : Commands)
|
||||||
{
|
{
|
||||||
if (params.size() >= 1)
|
if (params.size() >= 1)
|
||||||
{
|
{
|
||||||
@ -33,7 +33,10 @@ namespace Components
|
|||||||
{
|
{
|
||||||
push eax
|
push eax
|
||||||
pushad
|
pushad
|
||||||
|
|
||||||
|
// Missing localClientNum!
|
||||||
call ServerCommands::OnServerCommand
|
call ServerCommands::OnServerCommand
|
||||||
|
|
||||||
mov [esp + 20h], eax
|
mov [esp + 20h], eax
|
||||||
popad
|
popad
|
||||||
pop eax
|
pop eax
|
||||||
@ -63,7 +66,7 @@ namespace Components
|
|||||||
ServerCommands::ServerCommands()
|
ServerCommands::ServerCommands()
|
||||||
{
|
{
|
||||||
// Server command receive hook
|
// Server command receive hook
|
||||||
Utils::Hook(0x59449F, ServerCommands::CG_DeployServerCommand_Stub).install()->quick();
|
Utils::Hook(0x59449F, CG_DeployServerCommand_Stub).install()->quick();
|
||||||
Utils::Hook::Nop(0x5944A4, 6);
|
Utils::Hook::Nop(0x5944A4, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,11 @@ namespace Components
|
|||||||
public:
|
public:
|
||||||
ServerCommands();
|
ServerCommands();
|
||||||
|
|
||||||
static void OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> callback);
|
using serverCommandHandler = std::function<bool(Command::Params*)>;
|
||||||
|
static void OnCommand(std::int32_t cmd, const serverCommandHandler& callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> Commands;
|
static std::unordered_map<std::int32_t, serverCommandHandler> Commands;
|
||||||
|
|
||||||
static bool OnServerCommand();
|
static bool OnServerCommand();
|
||||||
static void CG_DeployServerCommand_Stub();
|
static void CG_DeployServerCommand_Stub();
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
#include "GSC/Script.hpp"
|
||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
int64_t* Stats::GetStatsID()
|
std::int64_t* Stats::GetStatsID()
|
||||||
{
|
{
|
||||||
static int64_t id = 0x110000100001337;
|
static std::int64_t id = 0x110000100001337;
|
||||||
return &id;
|
return &id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ namespace Components
|
|||||||
|
|
||||||
void Stats::UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
|
void Stats::UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
|
||||||
{
|
{
|
||||||
Stats::SendStats();
|
SendStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Stats::SaveStats(char* dest, const char* folder, const char* buffer, size_t length)
|
int Stats::SaveStats(char* dest, const char* folder, const char* buffer, size_t length)
|
||||||
@ -73,18 +74,64 @@ namespace Components
|
|||||||
return Utils::Hook::Call<int(char*, const char*, const char*, size_t)>(0x426450)(dest, folder, buffer, length);
|
return Utils::Hook::Call<int(char*, const char*, const char*, size_t)>(0x426450)(dest, folder, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stats::AddScriptFunctions()
|
||||||
|
{
|
||||||
|
Script::AddMethod("GetStat", [](const Game::scr_entref_t entref)
|
||||||
|
{
|
||||||
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
|
const auto index = Game::Scr_GetInt(0);
|
||||||
|
|
||||||
|
if (index < 0 || index > 3499)
|
||||||
|
{
|
||||||
|
Game::Scr_ParamError(0, Utils::String::VA("GetStat: invalid index %i", index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent->client->sess.connected <= Game::CON_DISCONNECTED)
|
||||||
|
{
|
||||||
|
Game::Scr_Error("GetStat: called on a disconnected player");
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::Scr_AddInt(Game::SV_GetClientStat(ent->s.number, index));
|
||||||
|
});
|
||||||
|
|
||||||
|
Script::AddMethod("SetStat", [](const Game::scr_entref_t entref)
|
||||||
|
{
|
||||||
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
|
|
||||||
|
const auto iNumParms = Game::Scr_GetNumParam();
|
||||||
|
if (iNumParms != 2)
|
||||||
|
{
|
||||||
|
Game::Scr_Error(Utils::String::VA("GetStat: takes 2 arguments, got %u.\n", iNumParms));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = Game::Scr_GetInt(0);
|
||||||
|
if (index < 0 || index > 3499)
|
||||||
|
{
|
||||||
|
Game::Scr_ParamError(0, Utils::String::VA("setstat: invalid index %i", index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = Game::Scr_GetInt(1);
|
||||||
|
if (index < 2000 && (value < 0 || value > 255))
|
||||||
|
{
|
||||||
|
Game::Scr_ParamError(1, Utils::String::VA("setstat: index %i is a byte value, and you're trying to set it to %i", index, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::SV_SetClientStat(ent->s.number, index, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Stats::Stats()
|
Stats::Stats()
|
||||||
{
|
{
|
||||||
// This UIScript should be added in the onClose code of the cac_popup menu,
|
// This UIScript should be added in the onClose code of the cac_popup menu,
|
||||||
// so everytime the create-a-class window is closed, and a client is connected
|
// so everytime the create-a-class window is closed, and a client is connected
|
||||||
// to a server, the stats data of the client will be reuploaded to the server.
|
// to a server, the stats data of the client will be reuploaded to the server.
|
||||||
// allowing the player to change their classes while connected to a server.
|
// allowing the player to change their classes while connected to a server.
|
||||||
UIScript::Add("UpdateClasses", Stats::UpdateClasses);
|
UIScript::Add("UpdateClasses", UpdateClasses);
|
||||||
|
|
||||||
// Allow playerdata to be changed while connected to a server
|
// Allow playerdata to be changed while connected to a server
|
||||||
Utils::Hook::Set<BYTE>(0x4376FD, 0xEB);
|
Utils::Hook::Set<BYTE>(0x4376FD, 0xEB);
|
||||||
|
|
||||||
// ToDo: Allow playerdata changes in setPlayerData UI script.
|
// TODO: Allow playerdata changes in setPlayerData UI script.
|
||||||
|
|
||||||
// Rename stat file
|
// Rename stat file
|
||||||
Utils::Hook::SetString(0x71C048, "iw4x.stat");
|
Utils::Hook::SetString(0x71C048, "iw4x.stat");
|
||||||
@ -92,8 +139,9 @@ namespace Components
|
|||||||
// Patch stats steamid
|
// Patch stats steamid
|
||||||
Utils::Hook::Nop(0x682EBF, 20);
|
Utils::Hook::Nop(0x682EBF, 20);
|
||||||
Utils::Hook::Nop(0x6830B1, 20);
|
Utils::Hook::Nop(0x6830B1, 20);
|
||||||
Utils::Hook(0x682EBF, Stats::GetStatsID, HOOK_CALL).install()->quick();
|
|
||||||
Utils::Hook(0x6830B1, Stats::GetStatsID, HOOK_CALL).install()->quick();
|
Utils::Hook(0x682EBF, GetStatsID, HOOK_CALL).install()->quick();
|
||||||
|
Utils::Hook(0x6830B1, GetStatsID, HOOK_CALL).install()->quick();
|
||||||
//Utils::Hook::Set<BYTE>(0x68323A, 0xEB);
|
//Utils::Hook::Set<BYTE>(0x68323A, 0xEB);
|
||||||
|
|
||||||
// Never use remote stat saving
|
// Never use remote stat saving
|
||||||
@ -103,6 +151,34 @@ namespace Components
|
|||||||
Utils::Hook::Nop(0x402CE6, 2);
|
Utils::Hook::Nop(0x402CE6, 2);
|
||||||
|
|
||||||
// Write stats to mod folder if a mod is loaded
|
// Write stats to mod folder if a mod is loaded
|
||||||
Utils::Hook(0x682F7B, Stats::SaveStats, HOOK_CALL).install()->quick();
|
Utils::Hook(0x682F7B, SaveStats, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
|
AddScriptFunctions();
|
||||||
|
|
||||||
|
// Skip silly Com_Error (LiveStorage_SetStat)
|
||||||
|
Utils::Hook::Set<BYTE>(0x4CC5F9, 0xEB);
|
||||||
|
|
||||||
|
// 'M' Seems to be used on Xbox only for parsing platform specific ranks
|
||||||
|
ServerCommands::OnCommand('M', [](Command::Params* params)
|
||||||
|
{
|
||||||
|
const auto* arg1 = params->get(1);
|
||||||
|
const auto* arg2 = params->get(2);
|
||||||
|
|
||||||
|
Game::LiveStorage_SetStat(Game::CL_ControllerIndexFromClientNum(0), std::atoi(arg1), std::atoi(arg2));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Command::Add("statGet", []([[maybe_unused]] Command::Params* params)
|
||||||
|
{
|
||||||
|
if (params->size() < 2)
|
||||||
|
{
|
||||||
|
Logger::PrintError(Game::CON_CHANNEL_SERVER, "statget usage: statget <index>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = std::atoi(params->get(1));
|
||||||
|
const auto stat = Game::LiveStorage_GetStat(0, index);
|
||||||
|
Logger::Print(Game::CON_CHANNEL_SYSTEM, "Stat {}: {}\n", index, stat);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,12 @@ namespace Components
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
static void UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
||||||
|
|
||||||
static void SendStats();
|
static void SendStats();
|
||||||
static int SaveStats(char* dest, const char* folder, const char* buffer, size_t length);
|
static int SaveStats(char* dest, const char* folder, const char* buffer, size_t length);
|
||||||
|
|
||||||
static int64_t* GetStatsID();
|
static std::int64_t* GetStatsID();
|
||||||
|
|
||||||
|
static void AddScriptFunctions();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ namespace Game
|
|||||||
Live_GetLocalClientName_t Live_GetLocalClientName = Live_GetLocalClientName_t(0x441FC0);
|
Live_GetLocalClientName_t Live_GetLocalClientName = Live_GetLocalClientName_t(0x441FC0);
|
||||||
|
|
||||||
LiveStorage_GetStat_t LiveStorage_GetStat = LiveStorage_GetStat_t(0x471F60);
|
LiveStorage_GetStat_t LiveStorage_GetStat = LiveStorage_GetStat_t(0x471F60);
|
||||||
|
LiveStorage_SetStat_t LiveStorage_SetStat = LiveStorage_SetStat_t(0x4CC5D0);
|
||||||
|
|
||||||
Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0);
|
Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0);
|
||||||
|
|
||||||
|
@ -347,6 +347,9 @@ namespace Game
|
|||||||
typedef int(*LiveStorage_GetStat_t)(int controllerIndex, int index);
|
typedef int(*LiveStorage_GetStat_t)(int controllerIndex, int index);
|
||||||
extern LiveStorage_GetStat_t LiveStorage_GetStat;
|
extern LiveStorage_GetStat_t LiveStorage_GetStat;
|
||||||
|
|
||||||
|
typedef void(*LiveStorage_SetStat_t)(int controllerIndex, int index, int value);
|
||||||
|
extern LiveStorage_SetStat_t LiveStorage_SetStat;
|
||||||
|
|
||||||
typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive);
|
typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive);
|
||||||
extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer;
|
extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ namespace Game
|
|||||||
SV_IsTestClient_t SV_IsTestClient = SV_IsTestClient_t(0x4D6E40);
|
SV_IsTestClient_t SV_IsTestClient = SV_IsTestClient_t(0x4D6E40);
|
||||||
SV_GameClientNum_Score_t SV_GameClientNum_Score = SV_GameClientNum_Score_t(0x469AC0);
|
SV_GameClientNum_Score_t SV_GameClientNum_Score = SV_GameClientNum_Score_t(0x469AC0);
|
||||||
SV_GameSendServerCommand_t SV_GameSendServerCommand = SV_GameSendServerCommand_t(0x4BC3A0);
|
SV_GameSendServerCommand_t SV_GameSendServerCommand = SV_GameSendServerCommand_t(0x4BC3A0);
|
||||||
|
SV_SendServerCommand_t SV_SendServerCommand = SV_SendServerCommand_t(0x4255A0);
|
||||||
SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString = SV_Cmd_TokenizeString_t(0x4B5780);
|
SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString = SV_Cmd_TokenizeString_t(0x4B5780);
|
||||||
SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString = SV_Cmd_EndTokenizedString_t(0x464750);
|
SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString = SV_Cmd_EndTokenizedString_t(0x464750);
|
||||||
SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer = SV_Cmd_ArgvBuffer_t(0x40BB60);
|
SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer = SV_Cmd_ArgvBuffer_t(0x40BB60);
|
||||||
@ -52,6 +53,60 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SV_GetClientStat(int clientNum, int index)
|
||||||
|
{
|
||||||
|
assert(svs_clients[clientNum].statPacketsReceived == (1 << MAX_STATPACKETS) - 1);
|
||||||
|
assert(svs_clients[clientNum].header.state >= CS_CONNECTED);
|
||||||
|
|
||||||
|
if (index < 2000)
|
||||||
|
{
|
||||||
|
// Skip first 4 bytes of the binary blob
|
||||||
|
return svs_clients[clientNum].stats.__s0.binary[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 3498)
|
||||||
|
{
|
||||||
|
return svs_clients[clientNum].stats.__s0.data[index - 2000];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0 && "Unhandled stat index");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_SetClientStat(int clientNum, int index, int value)
|
||||||
|
{
|
||||||
|
assert(svs_clients[clientNum].statPacketsReceived == (1 << MAX_STATPACKETS) - 1);
|
||||||
|
assert(svs_clients[clientNum].header.state >= CS_CONNECTED);
|
||||||
|
|
||||||
|
if (index < 2000)
|
||||||
|
{
|
||||||
|
assert(value >= 0 && value <= 255);
|
||||||
|
|
||||||
|
if (svs_clients[clientNum].stats.__s0.binary[index] == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
svs_clients[clientNum].stats.__s0.binary[index] = static_cast<unsigned char>(value);
|
||||||
|
}
|
||||||
|
else if (index < 3498)
|
||||||
|
{
|
||||||
|
if (svs_clients[clientNum].stats.__s0.data[index - 2000] == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
svs_clients[clientNum].stats.__s0.data[index - 2000] = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0 && "Unhandled stat index");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SV_SendServerCommand(&svs_clients[clientNum], SV_CMD_RELIABLE, "%c %i %i", 'M', index, value);
|
||||||
|
}
|
||||||
|
|
||||||
void SV_BotUserMove(client_t* client)
|
void SV_BotUserMove(client_t* client)
|
||||||
{
|
{
|
||||||
static DWORD SV_BotUserMove_t = 0x626E50;
|
static DWORD SV_BotUserMove_t = 0x626E50;
|
||||||
|
@ -14,6 +14,9 @@ namespace Game
|
|||||||
typedef void(*SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char* text);
|
typedef void(*SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char* text);
|
||||||
extern SV_GameSendServerCommand_t SV_GameSendServerCommand;
|
extern SV_GameSendServerCommand_t SV_GameSendServerCommand;
|
||||||
|
|
||||||
|
typedef void(*SV_SendServerCommand_t)(client_t* cl, svscmd_type type, const char* fmt, ...);
|
||||||
|
extern SV_SendServerCommand_t SV_SendServerCommand;
|
||||||
|
|
||||||
typedef void(*SV_Cmd_TokenizeString_t)(const char* string);
|
typedef void(*SV_Cmd_TokenizeString_t)(const char* string);
|
||||||
extern SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString;
|
extern SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString;
|
||||||
|
|
||||||
@ -47,6 +50,8 @@ namespace Game
|
|||||||
typedef client_t* (*SV_FindClientByAddress_t)(netadr_t from, int qport, int remoteClientIndex);
|
typedef client_t* (*SV_FindClientByAddress_t)(netadr_t from, int qport, int remoteClientIndex);
|
||||||
extern SV_FindClientByAddress_t SV_FindClientByAddress;
|
extern SV_FindClientByAddress_t SV_FindClientByAddress;
|
||||||
|
|
||||||
|
constexpr auto MAX_STATPACKETS = 7;
|
||||||
|
|
||||||
extern int* svs_time;
|
extern int* svs_time;
|
||||||
extern int* sv_serverId_value;
|
extern int* sv_serverId_value;
|
||||||
extern int* svs_clientCount;
|
extern int* svs_clientCount;
|
||||||
@ -57,5 +62,7 @@ namespace Game
|
|||||||
extern int SV_GetServerThreadOwnsGame();
|
extern int SV_GetServerThreadOwnsGame();
|
||||||
extern void SV_GameDropClient(int clientNum, const char* reason);
|
extern void SV_GameDropClient(int clientNum, const char* reason);
|
||||||
extern void SV_DropAllBots();
|
extern void SV_DropAllBots();
|
||||||
|
extern int SV_GetClientStat(int clientNum, int index);
|
||||||
|
extern void SV_SetClientStat(int clientNum, int index, int value);
|
||||||
extern void SV_BotUserMove(client_t* client);
|
extern void SV_BotUserMove(client_t* client);
|
||||||
}
|
}
|
||||||
|
@ -6023,12 +6023,6 @@ namespace Game
|
|||||||
float keys[1];
|
float keys[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
union $81775853B5F1E1C6748A82ED93FC367C
|
|
||||||
{
|
|
||||||
FxElemVisuals visuals[32];
|
|
||||||
FxElemMarkVisuals markVisuals[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxEditorTrailDef
|
struct FxEditorTrailDef
|
||||||
{
|
{
|
||||||
FxTrailVertex verts[64];
|
FxTrailVertex verts[64];
|
||||||
@ -6081,7 +6075,11 @@ namespace Game
|
|||||||
FxFloatRange emitDistVariance;
|
FxFloatRange emitDistVariance;
|
||||||
char elemType;
|
char elemType;
|
||||||
int visualCount;
|
int visualCount;
|
||||||
$81775853B5F1E1C6748A82ED93FC367C ___u42;
|
union
|
||||||
|
{
|
||||||
|
FxElemVisuals visuals[32];
|
||||||
|
FxElemMarkVisuals markVisuals[16];
|
||||||
|
} ___u42;
|
||||||
int trailSplitDist;
|
int trailSplitDist;
|
||||||
int trailSplitArcDist;
|
int trailSplitArcDist;
|
||||||
int trailSplitTime;
|
int trailSplitTime;
|
||||||
@ -6583,7 +6581,15 @@ namespace Game
|
|||||||
int bIsTestClient; // 269040
|
int bIsTestClient; // 269040
|
||||||
int serverID; // 269044
|
int serverID; // 269044
|
||||||
bool usingOnlineStatsOffline;
|
bool usingOnlineStatsOffline;
|
||||||
char stats[8192];
|
struct
|
||||||
|
{
|
||||||
|
unsigned int checksum;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char binary[2000];
|
||||||
|
int data[1547];
|
||||||
|
} __s0;
|
||||||
|
} stats;
|
||||||
char statsModifiedFlags[1024];
|
char statsModifiedFlags[1024];
|
||||||
bool statsModified;
|
bool statsModified;
|
||||||
char statPacketsReceived;
|
char statPacketsReceived;
|
||||||
|
Loading…
Reference in New Issue
Block a user