2022-02-27 07:53:44 -05:00
|
|
|
#include <STDInclude.hpp>
|
2017-02-25 19:36:37 -05:00
|
|
|
|
|
|
|
namespace Components
|
|
|
|
{
|
2017-06-29 09:54:40 -04:00
|
|
|
int64_t* Stats::GetStatsID()
|
|
|
|
{
|
|
|
|
static int64_t id = 0x110000100001337;
|
|
|
|
return &id;
|
|
|
|
}
|
|
|
|
|
2017-02-26 15:34:18 -05:00
|
|
|
bool Stats::IsMaxLevel()
|
|
|
|
{
|
|
|
|
// 2516000 should be the max experience.
|
2017-02-28 05:40:33 -05:00
|
|
|
return (Game::Live_GetXp(0) >= Game::CL_GetMaxXP());
|
2017-02-26 15:34:18 -05:00
|
|
|
}
|
|
|
|
|
2017-02-25 19:36:37 -05:00
|
|
|
void Stats::SendStats()
|
|
|
|
{
|
|
|
|
// check if we're connected to a server...
|
|
|
|
if (*reinterpret_cast<std::uint32_t*>(0xB2C540) >= 7)
|
|
|
|
{
|
2017-04-24 16:33:13 -04:00
|
|
|
for (unsigned char i = 0; i < 7; ++i)
|
2017-02-25 19:36:37 -05:00
|
|
|
{
|
|
|
|
Game::Com_Printf(0, "Sending stat packet %i to server.\n", i);
|
|
|
|
|
|
|
|
// alloc
|
2022-08-13 11:19:45 -04:00
|
|
|
Game::msg_t msg{};
|
|
|
|
unsigned char buffer[2048]{};
|
2017-02-25 19:36:37 -05:00
|
|
|
|
|
|
|
// init
|
2017-02-28 07:36:38 -05:00
|
|
|
Game::MSG_Init(&msg, buffer, sizeof(buffer));
|
2017-02-25 19:36:37 -05:00
|
|
|
Game::MSG_WriteString(&msg, "stats");
|
|
|
|
|
|
|
|
// get stat buffer
|
|
|
|
char *statbuffer = nullptr;
|
|
|
|
if (Utils::Hook::Call<int(int)>(0x444CA0)(0))
|
|
|
|
{
|
|
|
|
statbuffer = &Utils::Hook::Call<char *(int)>(0x4C49F0)(0)[1240 * i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Client port?
|
2017-02-28 05:40:33 -05:00
|
|
|
Game::MSG_WriteShort(&msg, *reinterpret_cast<short*>(0xA1E878));
|
2017-02-25 19:36:37 -05:00
|
|
|
|
|
|
|
// Stat packet index
|
|
|
|
Game::MSG_WriteByte(&msg, i);
|
|
|
|
|
|
|
|
// write stat packet data
|
|
|
|
if (statbuffer)
|
|
|
|
{
|
2017-02-28 10:56:14 -05:00
|
|
|
Game::MSG_WriteData(&msg, statbuffer, std::min(8192 - (i * 1240), 1240));
|
2017-02-25 19:36:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// send statpacket
|
2022-08-13 11:19:45 -04:00
|
|
|
Network::SendRaw(Game::NS_CLIENT1, *reinterpret_cast<Game::netadr_t*>(0xA1E888), std::string(reinterpret_cast<char*>(msg.data), msg.cursize));
|
2017-02-25 19:36:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 10:38:14 -04:00
|
|
|
void Stats::UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
|
2017-02-25 19:36:37 -05:00
|
|
|
{
|
2017-03-04 07:51:41 -05:00
|
|
|
Stats::SendStats();
|
2017-02-25 19:36:37 -05:00
|
|
|
}
|
|
|
|
|
2019-10-01 09:06:40 -04:00
|
|
|
int Stats::SaveStats(char* dest, const char* folder, const char* buffer, size_t length)
|
|
|
|
{
|
2022-08-10 17:03:26 -04:00
|
|
|
assert(*Game::fs_gameDirVar);
|
2020-08-08 06:19:55 -04:00
|
|
|
|
2022-08-10 17:03:26 -04:00
|
|
|
if (!std::strcmp((*Game::fs_gameDirVar)->current.string, "mods/"))
|
2019-10-01 09:06:40 -04:00
|
|
|
{
|
2022-08-10 17:03:26 -04:00
|
|
|
folder = (*Game::fs_gameDirVar)->current.string;
|
2019-10-01 09:06:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return Utils::Hook::Call<int(char*, const char*, const char*, size_t)>(0x426450)(dest, folder, buffer, length);
|
|
|
|
}
|
|
|
|
|
2017-02-25 19:36:37 -05:00
|
|
|
Stats::Stats()
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
// 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.
|
|
|
|
UIScript::Add("UpdateClasses", Stats::UpdateClasses);
|
|
|
|
|
|
|
|
// Allow playerdata to be changed while connected to a server
|
|
|
|
Utils::Hook::Set<BYTE>(0x4376FD, 0xEB);
|
|
|
|
|
|
|
|
// ToDo: Allow playerdata changes in setPlayerData UI script.
|
2017-06-29 09:54:40 -04:00
|
|
|
|
|
|
|
// Rename stat file
|
|
|
|
Utils::Hook::SetString(0x71C048, "iw4x.stat");
|
|
|
|
|
|
|
|
// Patch stats steamid
|
|
|
|
Utils::Hook::Nop(0x682EBF, 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::Set<BYTE>(0x68323A, 0xEB);
|
|
|
|
|
|
|
|
// Never use remote stat saving
|
|
|
|
Utils::Hook::Set<BYTE>(0x682F39, 0xEB);
|
|
|
|
|
|
|
|
// Don't create stat backup
|
|
|
|
Utils::Hook::Nop(0x402CE6, 2);
|
2019-10-01 09:06:40 -04:00
|
|
|
|
|
|
|
// Write stats to mod folder if a mod is loaded
|
|
|
|
Utils::Hook(0x682F7B, Stats::SaveStats, HOOK_CALL).install()->quick();
|
2017-02-25 19:36:37 -05:00
|
|
|
}
|
|
|
|
}
|