diff --git a/src/Components/Modules/ModList.cpp b/src/Components/Modules/ModList.cpp index 2b3a07f6..34ec0033 100644 --- a/src/Components/Modules/ModList.cpp +++ b/src/Components/Modules/ModList.cpp @@ -59,8 +59,8 @@ namespace Components void ModList::UIScript_ClearMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto fsGame = Dvar::Var("fs_game"); - fsGame.set(""); + Game::Dvar_SetString(*Game::fs_gameDirVar, ""); + const_cast((*Game::fs_gameDirVar))->modified = true; if (Dvar::Var("cl_modVidRestart").get()) { @@ -74,8 +74,8 @@ namespace Components void ModList::RunMod(const std::string& mod) { - auto fsGame = Dvar::Var("fs_game"); - fsGame.set(std::format("mods/{}", mod)); + Game::Dvar_SetString(*Game::fs_gameDirVar, Utils::String::Format("mods/{}", mod)); + const_cast((*Game::fs_gameDirVar))->modified = true; if (Dvar::Var("cl_modVidRestart").get()) { diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp index e8b491f1..6b6bcf8d 100644 --- a/src/Components/Modules/Theatre.cpp +++ b/src/Components/Modules/Theatre.cpp @@ -177,6 +177,28 @@ namespace Components } } + void Theatre::CL_WriteDemoClientArchive_Hk(void(*write)(const void* buffer, int len, int localClientNum), const Game::playerState_s* ps, const float* viewangles, [[maybe_unused]] const float* selectedLocation, [[maybe_unused]] const float selectedLocationAngle, int localClientNum, int index) + { + assert(write); + assert(ps); + + const unsigned char msgType = 1; + (write)(&msgType, sizeof(unsigned char), localClientNum); + + (write)(&index, sizeof(int), localClientNum); + + (write)(ps->origin, sizeof(float[3]), localClientNum); + (write)(ps->velocity, sizeof(float[3]), localClientNum); + (write)(&ps->movementDir, sizeof(int), localClientNum); + (write)(&ps->bobCycle, sizeof(int), localClientNum); + (write)(ps, sizeof(Game::playerState_s*), localClientNum); + (write)(viewangles, sizeof(float[3]), localClientNum); + + // Disable locationSelectionInfo + const auto locationSelectionInfo = 0; + (write)(&locationSelectionInfo, sizeof(int), localClientNum); + } + void Theatre::RecordStub(int channel, char* message, char* file) { Game::Com_Printf(channel, message, file); @@ -367,6 +389,9 @@ namespace Components Utils::Hook(0x50320E, AdjustTimeDeltaStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A8E03, ServerTimedOutStub, HOOK_JUMP).install()->quick(); + // Fix issue with locationSelectionInfo by disabling it + Utils::Hook(0x5AC20F, CL_WriteDemoClientArchive_Hk, HOOK_CALL).install()->quick(); + // Hook commands to enforce metadata generation Utils::Hook(0x5A82AE, RecordStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A8156, StopRecordStub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Theatre.hpp b/src/Components/Modules/Theatre.hpp index c5d0481e..63b45058 100644 --- a/src/Components/Modules/Theatre.hpp +++ b/src/Components/Modules/Theatre.hpp @@ -56,6 +56,8 @@ namespace Components static int CL_FirstSnapshot_Stub(); static void SV_SpawnServer_Stub(); + static void CL_WriteDemoClientArchive_Hk(void(*write)(const void* buffer, int len, int localClientNum), const Game::playerState_s* ps, const float* viewangles, const float* selectedLocation, float selectedLocationAngle, int localClientNum, int index); + static void RecordStub(int channel, char* message, char* file); static void StopRecordStub(int channel, char* message); }; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index e39fbdbc..ca4a7f8d 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1968,7 +1968,6 @@ namespace Game CMD_BUTTON_THROW = 1 << 19, }; -#pragma pack(push, 4) struct usercmd_s { int serverTime; @@ -1985,7 +1984,8 @@ namespace Game char selectedLocAngle; char remoteControlAngles[2]; }; -#pragma pack(pop) + + static_assert(sizeof(usercmd_s) == 0x28); enum trType_t { @@ -8654,7 +8654,20 @@ namespace Game CUBEMAPSHOT_COUNT = 0x7, }; - struct __declspec(align(8)) cg_s + struct snapshot_s + { + playerState_s ps; + int snapFlags; + int ping; + int serverTime; + int numEntities; + int numClients; + entityState_s entities[768]; + clientState_s clients[18]; + int serverCommandSequence; + }; + + struct cg_s { playerState_s predictedPlayerState; centity_s predictedPlayerEntity; @@ -8670,9 +8683,10 @@ namespace Game int latestSnapshotNum; int latestSnapshotTime; char pad0[16]; - void* snap; - void* nextSnap; - char _pad1[0x673DC]; + snapshot_s* snap; + snapshot_s* nextSnap; + snapshot_s activeSnapshots[2]; + float frameInterpolation; int frametime; // + 0x6A754 int time; int oldTime; @@ -8689,6 +8703,8 @@ namespace Game }; static_assert(sizeof(cg_s) == 0xFD540); + static_assert(offsetof(cg_s, frametime) == 0x6A754); + static_assert(offsetof(cg_s, selectedLocation) == 0x73DE0); static constexpr auto MAX_GPAD_COUNT = 1;