From 0bcbd75787db2d98a41325b3d23b8872502f0d5b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 9 Jan 2016 20:56:28 +0100 Subject: [PATCH] Theater stuff. --- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 1 + src/Components/Modules/Theatre.cpp | 167 +++++++++++++++++++++++++++++ src/Components/Modules/Theatre.hpp | 25 +++++ src/Game/Functions.cpp | 16 +++ src/Game/Functions.hpp | 43 ++++++++ src/Game/Structs.hpp | 16 +-- 7 files changed, 262 insertions(+), 7 deletions(-) create mode 100644 src/Components/Modules/Theatre.cpp create mode 100644 src/Components/Modules/Theatre.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 54d21683..2594a5b0 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -21,6 +21,7 @@ namespace Components Loader::Register(new Console()); Loader::Register(new IPCPipe()); Loader::Register(new Network()); + Loader::Register(new Theatre()); Loader::Register(new Download()); Loader::Register(new Playlist()); Loader::Register(new RawFiles()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 2bbbc0e1..3facb3a0 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -32,6 +32,7 @@ namespace Components #include "Modules\Console.hpp" #include "Modules\IPCPipe.hpp" #include "Modules\Network.hpp" +#include "Modules\Theatre.hpp" #include "Modules\Party.hpp" // Destroys the order, but requires network classes :D #include "Modules\Download.hpp" #include "Modules\Playlist.hpp" diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp new file mode 100644 index 00000000..37818696 --- /dev/null +++ b/src/Components/Modules/Theatre.cpp @@ -0,0 +1,167 @@ +#include "STDInclude.hpp" + +namespace Components +{ + char Theatre::BaselineSnapshot[131072] = { 0 }; + PBYTE Theatre::BaselineSnapshotMsg = 0; + int Theatre::BaselineSnapshotMsgLen; + int Theatre::BaselineSnapshotMsgOff; + + void Theatre::GamestateWriteStub(Game::msg_t* msg, char byte) + { + Game::MSG_WriteLong(msg, 0); + Game::MSG_WriteByte(msg, byte); + } + + void Theatre::RecordGamestateStub() + { + int sequence = (*Game::serverMessageSequence - 1); + Game::FS_Write(&sequence, 4, *Game::demoFile); + } + + void __declspec(naked) Theatre::BaselineStoreStub() + { + // Store snapshot message + __asm mov Theatre::BaselineSnapshotMsg, edi + + // Store offset and length + Theatre::BaselineSnapshotMsgLen = *(int*)(Theatre::BaselineSnapshotMsg + 20); + Theatre::BaselineSnapshotMsgOff = *(int*)(Theatre::BaselineSnapshotMsg + 28) - 7; + + // Copy to our snapshot buffer + memcpy(Theatre::BaselineSnapshot, *(DWORD**)(Theatre::BaselineSnapshotMsg + 8), *(DWORD*)(Theatre::BaselineSnapshotMsg + 20)); + + __asm + { + mov edx, 5ABEF5h + jmp edx + } + } + + void Theatre::WriteBaseline() + { + static char bufData[131072]; + static char cmpData[131072]; + + Game::msg_t buf; + + Game::MSG_Init(&buf, bufData, 131072); + Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff); + Game::MSG_WriteByte(&buf, 6); + + int compressedSize = Game::MSG_WriteBitsCompress(false, buf.data, cmpData, buf.cursize); + int fileCompressedSize = compressedSize + 4; + + int byte8 = 8; + char byte0 = 0; + + Game::FS_Write(&byte0, 1, *Game::demoFile); + Game::FS_Write(Game::serverMessageSequence, 4, *Game::demoFile); + Game::FS_Write(&fileCompressedSize, 4, *Game::demoFile); + Game::FS_Write(&byte8, 4, *Game::demoFile); + + for (int i = 0; i < compressedSize; i += 1024) + { + int size = min(compressedSize - i, 1024); + + if (i + size >= sizeof(cmpData)) + { + Logger::Print("Error: Writing compressed demo baseline exceeded buffer\n"); + break; + } + + Game::FS_Write(&cmpData[i], size, *Game::demoFile); + } + } + + void __declspec(naked) Theatre::BaselineToFileStub() + { + __asm + { + call Theatre::WriteBaseline + + // Restore overwritten operation + mov ecx, 0A5E9C4h + mov [ecx], 0 + + // Return to original code + mov ecx, 5A863Ah + jmp ecx + } + } + + void __declspec(naked) Theatre::AdjustTimeDeltaStub() + { + __asm + { + mov eax, Game::demoPlaying + mov eax, [eax] + test al, al + jz continue + + // delta doesn't drift for demos + retn + + continue: + mov eax, 5A1AD0h + jmp eax + } + } + + void __declspec(naked) Theatre::ServerTimedOutStub() + { + __asm + { + mov eax, Game::demoPlaying + mov eax, [eax] + test al, al + jz continue + + mov eax, 5A8E70h + jmp eax + + continue: + mov eax, 0B2BB90h + mov esi, 5A8E08h + jmp esi + } + } + + void __declspec(naked) Theatre::UISetActiveMenuStub() + { + if (*Game::demoPlaying == 1) + { + __asm + { + mov eax, 4CB49Ch + jmp eax + } + } + + __asm + { + mov ecx, [esp + 10h] + push 10h + push ecx + mov eax, 4CB3F6h + jmp eax + } + } + + Theatre::Theatre() + { + Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x5A85D2, Theatre::RecordGamestateStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x5ABE36, Theatre::BaselineStoreStub, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x5A8630, Theatre::BaselineToFileStub, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x4CB3EF, Theatre::UISetActiveMenuStub, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x5A8E03, Theatre::ServerTimedOutStub, HOOK_JUMP).Install()->Quick(); + + // set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps + if(!Dedicated::IsDedicated()) Utils::Hook::Set(0x47440B, "mp/defaultStringTable.csv"); + + *(BYTE*)0x5AC854 = 4; + *(BYTE*)0x5AC85A = 4; + } +} diff --git a/src/Components/Modules/Theatre.hpp b/src/Components/Modules/Theatre.hpp new file mode 100644 index 00000000..31756696 --- /dev/null +++ b/src/Components/Modules/Theatre.hpp @@ -0,0 +1,25 @@ +namespace Components +{ + class Theatre : public Component + { + public: + Theatre(); + const char* GetName() { return "Theatre"; }; + + private: + static char BaselineSnapshot[131072]; + static PBYTE BaselineSnapshotMsg; + static int BaselineSnapshotMsgLen; + static int BaselineSnapshotMsgOff; + + static void WriteBaseline(); + + static void GamestateWriteStub(Game::msg_t* msg, char byte); + static void RecordGamestateStub(); + static void BaselineStoreStub(); + static void BaselineToFileStub(); + static void AdjustTimeDeltaStub(); + static void ServerTimedOutStub(); + static void UISetActiveMenuStub(); + }; +} diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index acf79366..a7cf2760 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -62,6 +62,18 @@ namespace Game Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0; Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60; + MSG_Init_t MSG_Init = (MSG_Init_t)0x45FCA0; + MSG_ReadData_t MSG_ReadData = (MSG_ReadData_t)0x4527C0; + MSG_ReadLong_t MSG_ReadLong = (MSG_ReadLong_t)0x4C9550; + MSG_ReadShort_t MSG_ReadShort = (MSG_ReadShort_t)0x40BDD0; + MSG_ReadInt64_t MSG_ReadInt64 = (MSG_ReadInt64_t)0x4F1850; + MSG_ReadString_t MSG_ReadString = (MSG_ReadString_t)0x60E2B0; + MSG_WriteByte_t MSG_WriteByte = (MSG_WriteByte_t)0x48C520; + MSG_WriteData_t MSG_WriteData = (MSG_WriteData_t)0x4F4120; + MSG_WriteLong_t MSG_WriteLong = (MSG_WriteLong_t)0x41CA20; + MSG_WriteBitsCompress_t MSG_WriteBitsCompress = (MSG_WriteBitsCompress_t)0x4319D0; + MSG_ReadByte_t MSG_ReadByte = (MSG_ReadByte_t)0x4C1C20; + NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880; NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0; NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0; @@ -140,6 +152,10 @@ namespace Game int* numIP = (int*)0x64A1E68; netIP_t* localIP = (netIP_t*)0x64A1E28; + int* demoFile = (int*)0xA5EA1C; + int* demoPlaying = (int*)0xA5EA0C; + int* serverMessageSequence = (int*)0xA3E9B4; + void* ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 306e118a..3fed37a1 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -145,6 +145,45 @@ namespace Game typedef int(__cdecl * Menus_OpenByName_t)(UiContext *dc, const char *p); extern Menus_OpenByName_t Menus_OpenByName; + typedef void(__cdecl * MSG_Init_t)(void* msg, void* data, int maxsize); + extern MSG_Init_t MSG_Init; + + typedef int(__cdecl * MSG_ReadData_t)(msg_t* msg, char*, size_t); + extern MSG_ReadData_t MSG_ReadData; + + typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg); + extern MSG_ReadLong_t MSG_ReadLong; + + typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg); + extern MSG_ReadShort_t MSG_ReadShort; + + typedef __int64(__cdecl * MSG_ReadInt64_t)(msg_t* msg); + extern MSG_ReadInt64_t MSG_ReadInt64; + + typedef char* (__cdecl * MSG_ReadString_t)(msg_t*); + extern MSG_ReadString_t MSG_ReadString; + + typedef void(__cdecl * MSG_WriteByte_t)(msg_t* msg, unsigned char); + extern MSG_WriteByte_t MSG_WriteByte; + + typedef void(__cdecl * MSG_WriteData_t)(msg_t* msg, char*, size_t); + extern MSG_WriteData_t MSG_WriteData; + + typedef void(__cdecl * MSG_WriteLong_t)(msg_t* msg, int); + extern MSG_WriteLong_t MSG_WriteLong; + + typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size); + extern MSG_WriteBitsCompress_t MSG_WriteBitsCompress; + + typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg); + extern MSG_ReadShort_t MSG_ReadShort; + + typedef __int64(__cdecl * MSG_ReadInt64_t)(msg_t* msg); + extern MSG_ReadInt64_t MSG_ReadInt64; + + typedef int(__cdecl * MSG_ReadByte_t)(msg_t* msg); + extern MSG_ReadByte_t MSG_ReadByte; + typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr); extern NET_AdrToString_t NET_AdrToString; @@ -271,6 +310,10 @@ namespace Game extern int* numIP; extern netIP_t* localIP; + extern int* demoFile; + extern int* demoPlaying; + extern int* serverMessageSequence; + void* ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_t* item); void OOBPrintT(int type, netadr_t netadr, const char* message); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 912c9f49..a34b68f4 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -644,14 +644,16 @@ namespace Game typedef struct { - int unknown1; - int unknown2; - char* data; - int unknown3; - int maxsize; // 16 + int overflowed; + int readOnly; + char *data; + char *splitData; + int maxsize; int cursize; - int unknown4; - int readcount; // 28 + int splitSize; + int readcount; + int bit; + int lastEntityRef; } msg_t; #pragma pack(push, 1)