From 1176a15e714124a8eab673eae7c76a14a9cd9261 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Tue, 8 Dec 2020 16:14:47 -0600 Subject: [PATCH 1/2] [Script] Added Script Runtime Error printing when in Developer --- src/Components/Modules/Script.cpp | 247 ++++++++++++++++++++---------- src/Components/Modules/Script.hpp | 5 + 2 files changed, 175 insertions(+), 77 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 577687f4..732b5807 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -8,6 +8,7 @@ namespace Components std::vector Script::ScriptNameStack; unsigned short Script::FunctionName; std::unordered_map Script::ScriptStorage; + std::unordered_map Script::ScriptBaseProgramNum; Utils::Signal Script::VMShutdownSignal; @@ -282,15 +283,95 @@ namespace Components call Script::GetFunction add esp, 0Ch - returnSafe: + returnSafe: pop edi + pop esi + retn + } + } + + void Script::StoreScriptBaseProgramNum() + { + Script::ScriptBaseProgramNum.insert_or_assign(Utils::Hook::Get(0x1CFEEF8), Script::ScriptName); + } + + void Script::Scr_PrintPrevCodePos(int scriptPos) + { + int bestCodePos = -1; + int nextCodePos = -1; + int offset = -1; + std::string file; + + for (auto kv : Script::ScriptBaseProgramNum) + { + int codePos = kv.first; + + if (codePos > scriptPos) + { + if (nextCodePos == -1 || codePos < nextCodePos) + nextCodePos = codePos; + + continue; + } + + if (codePos < bestCodePos) + continue; + + bestCodePos = codePos; + + file = kv.second; + offset = scriptPos - bestCodePos; + } + + if (bestCodePos == -1) + return; + + float onehundred = 100.0; + + Logger::Print(23, "\n@ %d (%d - %d)\n", scriptPos, bestCodePos, nextCodePos); + Logger::Print(23, "in %s (%.1f%% through the source)\n\n", file.c_str(), ((offset * onehundred) / (nextCodePos - bestCodePos))); + } + + __declspec(naked) void Script::Scr_PrintPrevCodePosStub() + { + __asm + { + push esi + call Script::Scr_PrintPrevCodePos + add esp, 4h + pop esi retn } } + __declspec(naked) void Script::StoreScriptBaseProgramNumStub() + { + __asm + { + // execute our hook + pushad + pusha + + call Script::StoreScriptBaseProgramNum + + popa + popad + + // execute overwritten code caused by the jump hook + sub eax, ds:201A460h // gScrVarPub_programBuffer + add esp, 0Ch + mov ds : 1CFEEF8h, eax // gScrCompilePub_programLen + + // jump back to the original code + push 426C3Bh + retn + } + } + void Script::OnVMShutdown(Utils::Slot callback) { + Script::ScriptBaseProgramNum.clear(); Script::VMShutdownSignal.connect(callback); } @@ -336,121 +417,121 @@ namespace Components { // System time Script::AddFunction("GetSystemTime", [](Game::scr_entref_t) // gsc: GetSystemTime() - { - SYSTEMTIME time; - GetSystemTime(&time); + { + SYSTEMTIME time; + GetSystemTime(&time); - Game::Scr_AddInt(time.wSecond); - }); + Game::Scr_AddInt(time.wSecond); + }); Script::AddFunction("GetSystemMilliseconds", [](Game::scr_entref_t) // gsc: GetSystemMilliseconds() - { - SYSTEMTIME time; - GetSystemTime(&time); + { + SYSTEMTIME time; + GetSystemTime(&time); - Game::Scr_AddInt(time.wMilliseconds); - }); + Game::Scr_AddInt(time.wMilliseconds); + }); // Print to console, even without being in 'developer 1'. Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole() - { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - Game::Scr_Error("^1PrintConsole: Needs one string parameter!\n"); - return; - } + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) + { + Game::Scr_Error("^1PrintConsole: Needs one string parameter!\n"); + return; + } - auto str = Game::Scr_GetString(0); + auto str = Game::Scr_GetString(0); - Game::Com_Printf(0, str); - }); + Game::Com_Printf(0, str); + }); // Executes command to the console Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec() - { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - Game::Scr_Error("^1Exec: Needs one string parameter!\n"); - return; - } + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) + { + Game::Scr_Error("^1Exec: Needs one string parameter!\n"); + return; + } - auto str = Game::Scr_GetString(0); + auto str = Game::Scr_GetString(0); - Command::Execute(str, false); - }); + Command::Execute(str, false); + }); // Script Storage Funcs Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(, ); - { - if (Game::Scr_GetNumParam() != 2 || Game::Scr_GetType(0) != Game::VAR_STRING || Game::Scr_GetType(1) != Game::VAR_STRING) { - Game::Scr_Error("^1StorageSet: Needs two string parameters!\n"); - return; - } + if (Game::Scr_GetNumParam() != 2 || Game::Scr_GetType(0) != Game::VAR_STRING || Game::Scr_GetType(1) != Game::VAR_STRING) + { + Game::Scr_Error("^1StorageSet: Needs two string parameters!\n"); + return; + } - std::string key = Game::Scr_GetString(0); - std::string data = Game::Scr_GetString(1); + std::string key = Game::Scr_GetString(0); + std::string data = Game::Scr_GetString(1); - Script::ScriptStorage.insert_or_assign(key, data); - }); + Script::ScriptStorage.insert_or_assign(key, data); + }); Script::AddFunction("StorageRemove", [](Game::scr_entref_t) // gsc: StorageRemove(); - { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - Game::Scr_Error("^1StorageRemove: Needs one string parameter!\n"); - return; - } + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) + { + Game::Scr_Error("^1StorageRemove: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - if (!Script::ScriptStorage.contains(key)) - { - Game::Scr_Error(Utils::String::VA("^1StorageRemove: Store does not have key '%s'!\n", key.c_str())); - return; - } + if (!Script::ScriptStorage.contains(key)) + { + Game::Scr_Error(Utils::String::VA("^1StorageRemove: Store does not have key '%s'!\n", key.c_str())); + return; + } - Script::ScriptStorage.erase(key); - }); + Script::ScriptStorage.erase(key); + }); Script::AddFunction("StorageGet", [](Game::scr_entref_t) // gsc: StorageGet(); - { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - Game::Scr_Error("^1StorageGet: Needs one string parameter!\n"); - return; - } + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) + { + Game::Scr_Error("^1StorageGet: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - if (!Script::ScriptStorage.contains(key)) - { - Game::Scr_Error(Utils::String::VA("^1StorageGet: Store does not have key '%s'!\n", key.c_str())); - return; - } + if (!Script::ScriptStorage.contains(key)) + { + Game::Scr_Error(Utils::String::VA("^1StorageGet: Store does not have key '%s'!\n", key.c_str())); + return; + } - auto data = Script::ScriptStorage.at(key); - Game::Scr_AddString(data.c_str()); - }); + auto data = Script::ScriptStorage.at(key); + Game::Scr_AddString(data.c_str()); + }); Script::AddFunction("StorageHas", [](Game::scr_entref_t) // gsc: StorageHas(); - { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - Game::Scr_Error("^1StorageHas: Needs one string parameter!\n"); - return; - } + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) + { + Game::Scr_Error("^1StorageHas: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - Game::Scr_AddInt(Script::ScriptStorage.contains(key)); - }); + Game::Scr_AddInt(Script::ScriptStorage.contains(key)); + }); Script::AddFunction("StorageClear", [](Game::scr_entref_t) // gsc: StorageClear(); - { - Script::ScriptStorage.clear(); - }); + { + Script::ScriptStorage.clear(); + }); } Script::Script() @@ -458,6 +539,17 @@ namespace Components Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x426C2D, Script::StoreScriptBaseProgramNumStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x42281B, Script::Scr_PrintPrevCodePosStub, HOOK_JUMP).install()->quick(); + + // enable scr_error printing if in developer + Dvar::OnInit([]() + { + int developer = Dvar::Var("developer").get(); + + if (developer > 0) + Utils::Hook::Set(0x48D8C7, 0x75); + }); Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick(); @@ -475,9 +567,9 @@ namespace Components Utils::Hook(0x4D06BA, Script::ScrShutdownSystemStub, HOOK_CALL).install()->quick(); Script::AddFunction("debugBox", [](Game::scr_entref_t) - { - MessageBoxA(nullptr, Game::Scr_GetString(0), "DEBUG", 0); - }, true); + { + MessageBoxA(nullptr, Game::Scr_GetString(0), "DEBUG", 0); + }, true); Script::AddFunctions(); @@ -517,5 +609,6 @@ namespace Components Script::VMShutdownSignal.clear(); Script::ScriptStorage.clear(); + Script::ScriptBaseProgramNum.clear(); } } diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index 79b2bce2..49a75b78 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -39,6 +39,7 @@ namespace Components static std::vector ScriptNameStack; static unsigned short FunctionName; static std::unordered_map ScriptStorage; + static std::unordered_map Script::ScriptBaseProgramNum; static Utils::Signal VMShutdownSignal; @@ -61,6 +62,10 @@ namespace Components static void GetFunctionStub(); static void ScrShutdownSystemStub(int); + static void StoreScriptBaseProgramNumStub(); + static void StoreScriptBaseProgramNum(); + static void Scr_PrintPrevCodePosStub(); + static void Scr_PrintPrevCodePos(int); static int SetExpFogStub(); From 9f281ba3a1c95b99c2467f540f3cbef4d4ce19bd Mon Sep 17 00:00:00 2001 From: INeedBots Date: Tue, 8 Dec 2020 16:18:09 -0600 Subject: [PATCH 2/2] [Script] Fixed indents --- src/Components/Modules/Script.cpp | 168 +++++++++++++++--------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 732b5807..0e5bbd6d 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -283,10 +283,10 @@ namespace Components call Script::GetFunction add esp, 0Ch - returnSafe: + returnSafe: pop edi - pop esi - retn + pop esi + retn } } @@ -417,121 +417,121 @@ namespace Components { // System time Script::AddFunction("GetSystemTime", [](Game::scr_entref_t) // gsc: GetSystemTime() - { - SYSTEMTIME time; - GetSystemTime(&time); + { + SYSTEMTIME time; + GetSystemTime(&time); - Game::Scr_AddInt(time.wSecond); - }); + Game::Scr_AddInt(time.wSecond); + }); Script::AddFunction("GetSystemMilliseconds", [](Game::scr_entref_t) // gsc: GetSystemMilliseconds() - { - SYSTEMTIME time; - GetSystemTime(&time); + { + SYSTEMTIME time; + GetSystemTime(&time); - Game::Scr_AddInt(time.wMilliseconds); - }); + Game::Scr_AddInt(time.wMilliseconds); + }); // Print to console, even without being in 'developer 1'. Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole() + { + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) - { - Game::Scr_Error("^1PrintConsole: Needs one string parameter!\n"); - return; - } + Game::Scr_Error("^1PrintConsole: Needs one string parameter!\n"); + return; + } - auto str = Game::Scr_GetString(0); + auto str = Game::Scr_GetString(0); - Game::Com_Printf(0, str); - }); + Game::Com_Printf(0, str); + }); // Executes command to the console Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec() + { + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) - { - Game::Scr_Error("^1Exec: Needs one string parameter!\n"); - return; - } + Game::Scr_Error("^1Exec: Needs one string parameter!\n"); + return; + } - auto str = Game::Scr_GetString(0); + auto str = Game::Scr_GetString(0); - Command::Execute(str, false); - }); + Command::Execute(str, false); + }); // Script Storage Funcs Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(, ); + { + if (Game::Scr_GetNumParam() != 2 || Game::Scr_GetType(0) != Game::VAR_STRING || Game::Scr_GetType(1) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 2 || Game::Scr_GetType(0) != Game::VAR_STRING || Game::Scr_GetType(1) != Game::VAR_STRING) - { - Game::Scr_Error("^1StorageSet: Needs two string parameters!\n"); - return; - } + Game::Scr_Error("^1StorageSet: Needs two string parameters!\n"); + return; + } - std::string key = Game::Scr_GetString(0); - std::string data = Game::Scr_GetString(1); + std::string key = Game::Scr_GetString(0); + std::string data = Game::Scr_GetString(1); - Script::ScriptStorage.insert_or_assign(key, data); - }); + Script::ScriptStorage.insert_or_assign(key, data); + }); Script::AddFunction("StorageRemove", [](Game::scr_entref_t) // gsc: StorageRemove(); + { + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) - { - Game::Scr_Error("^1StorageRemove: Needs one string parameter!\n"); - return; - } + Game::Scr_Error("^1StorageRemove: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - if (!Script::ScriptStorage.contains(key)) - { - Game::Scr_Error(Utils::String::VA("^1StorageRemove: Store does not have key '%s'!\n", key.c_str())); - return; - } + if (!Script::ScriptStorage.contains(key)) + { + Game::Scr_Error(Utils::String::VA("^1StorageRemove: Store does not have key '%s'!\n", key.c_str())); + return; + } - Script::ScriptStorage.erase(key); - }); + Script::ScriptStorage.erase(key); + }); Script::AddFunction("StorageGet", [](Game::scr_entref_t) // gsc: StorageGet(); + { + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) - { - Game::Scr_Error("^1StorageGet: Needs one string parameter!\n"); - return; - } + Game::Scr_Error("^1StorageGet: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - if (!Script::ScriptStorage.contains(key)) - { - Game::Scr_Error(Utils::String::VA("^1StorageGet: Store does not have key '%s'!\n", key.c_str())); - return; - } + if (!Script::ScriptStorage.contains(key)) + { + Game::Scr_Error(Utils::String::VA("^1StorageGet: Store does not have key '%s'!\n", key.c_str())); + return; + } - auto data = Script::ScriptStorage.at(key); - Game::Scr_AddString(data.c_str()); - }); + auto data = Script::ScriptStorage.at(key); + Game::Scr_AddString(data.c_str()); + }); Script::AddFunction("StorageHas", [](Game::scr_entref_t) // gsc: StorageHas(); + { + if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) { - if (Game::Scr_GetNumParam() != 1 || Game::Scr_GetType(0) != Game::VAR_STRING) - { - Game::Scr_Error("^1StorageHas: Needs one string parameter!\n"); - return; - } + Game::Scr_Error("^1StorageHas: Needs one string parameter!\n"); + return; + } - std::string key = Game::Scr_GetString(0); + std::string key = Game::Scr_GetString(0); - Game::Scr_AddInt(Script::ScriptStorage.contains(key)); - }); + Game::Scr_AddInt(Script::ScriptStorage.contains(key)); + }); Script::AddFunction("StorageClear", [](Game::scr_entref_t) // gsc: StorageClear(); - { - Script::ScriptStorage.clear(); - }); + { + Script::ScriptStorage.clear(); + }); } Script::Script() @@ -544,12 +544,12 @@ namespace Components // enable scr_error printing if in developer Dvar::OnInit([]() - { - int developer = Dvar::Var("developer").get(); + { + int developer = Dvar::Var("developer").get(); - if (developer > 0) - Utils::Hook::Set(0x48D8C7, 0x75); - }); + if (developer > 0) + Utils::Hook::Set(0x48D8C7, 0x75); + }); Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick(); @@ -567,9 +567,9 @@ namespace Components Utils::Hook(0x4D06BA, Script::ScrShutdownSystemStub, HOOK_CALL).install()->quick(); Script::AddFunction("debugBox", [](Game::scr_entref_t) - { - MessageBoxA(nullptr, Game::Scr_GetString(0), "DEBUG", 0); - }, true); + { + MessageBoxA(nullptr, Game::Scr_GetString(0), "DEBUG", 0); + }, true); Script::AddFunctions();