diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index a31cc833..a3788975 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -17,7 +17,7 @@ namespace Components _time64(&time); ltime = _localtime64(&time); - strftime(filename, sizeof(filename) - 1, "iw4m-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime); + strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime); HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp index 73605a46..350086b7 100644 --- a/src/Components/Modules/Theatre.cpp +++ b/src/Components/Modules/Theatre.cpp @@ -263,14 +263,67 @@ namespace Components Dvar::Var("ui_demo_mapname").Set(info.Mapname); Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data())); Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data())); - Dvar::Var("ui_demo_length").Set(info.Length); // TODO: Parse as readable string + Dvar::Var("ui_demo_length").Set(Utils::FormatTimeSpan(info.Length)); // TODO: Parse as readable string Dvar::Var("ui_demo_author").Set(info.Author); Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp))); } } + uint32_t Theatre::InitCGameStub() + { + if (Dvar::Var("cl_autoRecord").Get() && !*Game::demoPlaying) + { + std::vector files; + std::vector demos = FileSystem::GetFileList("demos/", "dm_13"); + + for (auto demo : demos) + { + if (Utils::StartsWith(demo, "auto_")) + { + files.push_back(demo); + } + } + + int numDel = files.size() - Dvar::Var("cl_demosKeep").Get(); + + for (int i = 0; i < numDel; i++) + { + Logger::Print("Deleting old demo %s\n", files[i].data()); + FileSystem::DeleteFile("demos", files[i].data()); + FileSystem::DeleteFile("demos", Utils::VA("%s.json", files[i].data())); + } + + Command::Execute(Utils::VA("record auto_%I64d", time(0)), true); + } + + return Utils::Hook::Call(0x42BBB0)(); + } + + void Theatre::MapChangeStub() + { + if (*Game::demoRecording) + { + Command::Execute("stoprecord", true); + } + + Utils::Hook::Call(0x464A60)(); + } + + void Theatre::MapChangeSVStub(char* a1, char* a2) + { + if (*Game::demoRecording) + { + Command::Execute("stoprecord", true); + } + + Utils::Hook::Call(0x487C50)(a1, a2); + } + Theatre::Theatre() { + Dvar::Register("cl_autoRecord", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Automatically record games."); + Dvar::Register("cl_demosKeep", 30, 1, 999, Game::dvar_flag::DVAR_FLAG_SAVED, "How many demos to keep with autorecord."); + 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(); @@ -283,6 +336,11 @@ namespace Components Utils::Hook(0x5A82AE, Theatre::RecordStub, HOOK_CALL).Install()->Quick(); Utils::Hook(0x5A8156, Theatre::StopRecordStub, HOOK_CALL).Install()->Quick(); + // Autorecording + Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).Install()->Quick(); + // UIScripts UIScript::Add("loadDemos", Theatre::LoadDemos); UIScript::Add("launchDemo", Theatre::PlayDemo); diff --git a/src/Components/Modules/Theatre.hpp b/src/Components/Modules/Theatre.hpp index c0289f4f..01b8ad6a 100644 --- a/src/Components/Modules/Theatre.hpp +++ b/src/Components/Modules/Theatre.hpp @@ -61,6 +61,10 @@ namespace Components static void ServerTimedOutStub(); static void UISetActiveMenuStub(); + static uint32_t InitCGameStub(); + static void MapChangeStub(); + static void MapChangeSVStub(char* a1, char* a2); + static void RecordStub(int channel, char* message, char* file); static void StopRecordStub(int channel, char* message); }; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index a7cf2760..c0f27f93 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -154,6 +154,7 @@ namespace Game int* demoFile = (int*)0xA5EA1C; int* demoPlaying = (int*)0xA5EA0C; + int* demoRecording = (int*)0xA5EA08; int* serverMessageSequence = (int*)0xA3E9B4; void* ReallocateAssetPool(XAssetType type, unsigned int newSize) diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 4cbaa28d..bbbeeef5 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -312,6 +312,7 @@ namespace Game extern int* demoFile; extern int* demoPlaying; + extern int* demoRecording; extern int* serverMessageSequence; void* ReallocateAssetPool(XAssetType type, unsigned int newSize); diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index 337c9be9..6c2661de 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -25,9 +25,9 @@ namespace Utils return input; } - bool EndsWith(const char* heystack, const char* needle) + bool EndsWith(const char* haystack, const char* needle) { - return (strstr(heystack, needle) == (heystack + strlen(heystack) - strlen(needle))); + return (strstr(haystack, needle) == (haystack + strlen(haystack) - strlen(needle))); } std::vector Explode(const std::string& str, char delim) @@ -62,6 +62,11 @@ namespace Utils } } + bool StartsWith(std::string haystack, std::string needle) + { + return (haystack.size() >= needle.size() && !strncmp(needle.data(), haystack.data(), needle.size())); + } + unsigned int OneAtATime(const char *key, size_t len) { unsigned int hash, i; @@ -97,6 +102,17 @@ namespace Utils return LTrim(RTrim(s)); } + std::string FormatTimeSpan(int milliseconds) + { + int secondsTotal = milliseconds / 1000; + int seconds = secondsTotal % 60; + int minutesTotal = secondsTotal / 60; + int minutes = minutesTotal % 60; + int hoursTotal = minutesTotal / 60; + + return Utils::VA("%02d:%02d:%02d", hoursTotal, minutes, seconds); + } + std::string ParseChallenge(std::string data) { // Ensure line break diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index daf734ea..1d01257f 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -2,14 +2,16 @@ namespace Utils { const char *VA(const char *fmt, ...); std::string StrToLower(std::string input); - bool EndsWith(const char* heystack, const char* needle); + bool EndsWith(const char* haystack, const char* needle); std::vector Explode(const std::string& str, char delim); void Replace(std::string &string, std::string find, std::string replace); + bool StartsWith(std::string haystack, std::string needle); unsigned int OneAtATime(const char *key, size_t len); std::string <rim(std::string &s); std::string &RTrim(std::string &s); std::string &Trim(std::string &s); + std::string FormatTimeSpan(int milliseconds); std::string ParseChallenge(std::string data); bool FileExists(std::string file);