From 857cc9f415e8b5f5dc6e4c84e8e24b56d0e73187 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Wed, 23 Feb 2022 11:38:37 +0000 Subject: [PATCH 01/10] Differentiate between functions and methods (GSC) --- src/Components/Modules/Bots.cpp | 12 +- src/Components/Modules/ClientCommand.cpp | 10 +- src/Components/Modules/Download.cpp | 4 +- src/Components/Modules/Script.cpp | 149 ++++++++++++--------- src/Components/Modules/Script.hpp | 29 ++-- src/Components/Modules/ScriptExtension.cpp | 12 +- src/Game/Functions.hpp | 2 +- src/Game/Structs.hpp | 17 ++- 8 files changed, 134 insertions(+), 101 deletions(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 332b43c1..21261246 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -117,7 +117,7 @@ namespace Components void Bots::AddMethods() { - Script::AddFunction("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing() + Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing() { const auto ping = Game::Scr_GetInt(0); @@ -139,7 +139,7 @@ namespace Components client->ping = static_cast(ping); }); - Script::AddFunction("IsTestClient", [](Game::scr_entref_t entref) // Usage: IsTestClient(); + Script::AddMethod("IsTestClient", [](Game::scr_entref_t entref) // Usage: IsTestClient(); { const auto* gentity = Script::GetEntity(entref); const auto* client = Script::GetClient(gentity); @@ -147,7 +147,7 @@ namespace Components Game::Scr_AddBool(client->bIsTestClient == 1); }); - Script::AddFunction("BotStop", [](Game::scr_entref_t entref) // Usage: BotStop(); + Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: BotStop(); { const auto* gentity = Script::GetEntity(entref); const auto* client = Script::GetClient(gentity); @@ -163,7 +163,7 @@ namespace Components g_botai[entref.entnum].active = false; }); - Script::AddFunction("BotWeapon", [](Game::scr_entref_t entref) // Usage: BotWeapon(); + Script::AddMethod("BotWeapon", [](Game::scr_entref_t entref) // Usage: BotWeapon(); { const auto* weapon = Game::Scr_GetString(0); @@ -187,7 +187,7 @@ namespace Components g_botai[entref.entnum].active = true; }); - Script::AddFunction("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); + Script::AddMethod("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); { const auto* action = Game::Scr_GetString(0); @@ -229,7 +229,7 @@ namespace Components Game::Scr_ParamError(0, "^1BotAction: Unknown action.\n"); }); - Script::AddFunction("BotMovement", [](Game::scr_entref_t entref) // Usage: BotMovement(, ); + Script::AddMethod("BotMovement", [](Game::scr_entref_t entref) // Usage: BotMovement(, ); { auto forwardInt = Game::Scr_GetInt(0); auto rightInt = Game::Scr_GetInt(1); diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index 7236951c..5b7136c6 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -175,7 +175,7 @@ namespace Components void ClientCommand::AddScriptFunctions() { - Script::AddFunction("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(); + Script::AddMethod("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(); { const auto* ent = Script::GetEntity(entref); @@ -202,7 +202,7 @@ namespace Components } }); - Script::AddFunction("Ufo", [](Game::scr_entref_t entref) // gsc: Ufo(); + Script::AddMethod("Ufo", [](Game::scr_entref_t entref) // gsc: Ufo(); { const auto* ent = Script::GetEntity(entref); @@ -229,7 +229,7 @@ namespace Components } }); - Script::AddFunction("God", [](Game::scr_entref_t entref) // gsc: God(); + Script::AddMethod("God", [](Game::scr_entref_t entref) // gsc: God(); { auto* ent = Script::GetEntity(entref); @@ -250,7 +250,7 @@ namespace Components } }); - Script::AddFunction("Demigod", [](Game::scr_entref_t entref) // gsc: Demigod(); + Script::AddMethod("Demigod", [](Game::scr_entref_t entref) // gsc: Demigod(); { auto* ent = Script::GetEntity(entref); @@ -271,7 +271,7 @@ namespace Components } }); - Script::AddFunction("Notarget", [](Game::scr_entref_t entref) // gsc: Notarget(); + Script::AddMethod("Notarget", [](Game::scr_entref_t entref) // gsc: Notarget(); { auto* ent = Script::GetEntity(entref); diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 663cdae7..bcf334bc 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -964,7 +964,7 @@ namespace Components Download::ScriptDownloads.clear(); }); - Script::AddFunction("HttpGet", [](Game::scr_entref_t) + Script::AddFunction("HttpGet", []() { if (!Dedicated::IsEnabled() && !Flags::HasFlag("scriptablehttp")) return; @@ -984,7 +984,7 @@ namespace Components Game::RemoveRefToObject(object); }); - Script::AddFunction("HttpCancel", [](Game::scr_entref_t) + Script::AddFunction("HttpCancel", []() { if (!Dedicated::IsEnabled() && !Flags::HasFlag("scriptablehttp")) return; diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 42f401d9..1266ff72 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -4,7 +4,8 @@ namespace Components { std::string Script::ScriptName; std::vector Script::ScriptHandles; - std::vector Script::ScriptFunctions; + std::unordered_map Script::CustomScrFunctions; + std::unordered_map Script::CustomScrMethods; std::vector Script::ScriptNameStack; unsigned short Script::FunctionName; std::unordered_map Script::ScriptStorage; @@ -270,61 +271,77 @@ namespace Components Game::GScr_LoadGameTypeScript(); } - void Script::AddFunction(const std::string& name, Game::scr_function_t function, bool isDev) + void Script::AddFunction(const char* name, Game::xfunction_t func, int type) { - for (auto i = Script::ScriptFunctions.begin(); i != Script::ScriptFunctions.end();) - { - if (i->getName() == name) - { - i = Script::ScriptFunctions.erase(i); - continue; - } + Game::BuiltinFunctionDef toAdd; + toAdd.actionString = name; + toAdd.actionFunc = func; + toAdd.type = type; - ++i; - } - - Script::ScriptFunctions.push_back({ name, function, isDev }); + CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); } - Game::scr_function_t Script::GetFunction(void* caller, const char** name, int* isDev) + void Script::AddMethod(const char* name, Game::xmethod_t func, int type) { - for (auto& function : Script::ScriptFunctions) - { - if (name && *name) - { - if (Utils::String::ToLower(*name) == Utils::String::ToLower(function.getName())) - { - *name = function.getName(); - *isDev = function.isDev(); - return function.getFunction(); - } - } - else if (caller == reinterpret_cast(0x465781)) - { - Game::Scr_RegisterFunction(function.getFunction()); - } - } + Game::BuiltinMethodDef toAdd; + toAdd.actionString = name; + toAdd.actionFunc = func; + toAdd.type = type; - return nullptr; + CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); } - __declspec(naked) void Script::GetFunctionStub() + Game::xfunction_t Script::Scr_GetFunctionStub(const char** pName, int* type) { - __asm + for (const auto& [key, value] : Script::CustomScrFunctions) { - test eax, eax - jnz returnSafe - - sub esp, 8h - push [esp + 10h] - call Script::GetFunction - add esp, 0Ch - - returnSafe: - pop edi - pop esi - retn + Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), value.actionString); } + + return Utils::Hook::Call(0x44E700)(pName, type); // Scr_GetFunction + } + + Game::xmethod_t Script::Scr_GetMethodStub(const char** pName, int* type) + { + for (const auto& [key, value] : Script::CustomScrMethods) + { + Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), value.actionString); + } + + return Utils::Hook::Call(0x4EC870)(pName, type); // Scr_GetMethod + } + + Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type) + { + if (pName && *pName) + { + const auto got = Script::CustomScrFunctions.find(*pName); + + // If no function was found let's call game's function + if (got != Script::CustomScrFunctions.end()) + { + *type = got->second.type; + return got->second.actionFunc; + } + } + + return Utils::Hook::Call(0x5FA2B0)(pName, type); // BuiltIn_GetFunction + } + + Game::xmethod_t Script::Player_GetMethodStub(const char** pName) + { + if (pName && *pName) + { + const auto got = Script::CustomScrMethods.find(*pName); + + // If no method was found let's call game's function + if (got != Script::CustomScrMethods.end()) + { + return got->second.actionFunc; + } + } + + return Utils::Hook::Call(0x4C07D0)(pName); // Player_GetMethod } void Script::StoreScriptBaseProgramNum() @@ -519,12 +536,14 @@ namespace Components Game::gentity_t* Script::GetEntity(const Game::scr_entref_t entref) { - if (entref.classnum != 0 || entref.entnum >= Game::MAX_GENTITIES) + if (entref.classnum != 0) { Game::Scr_ObjectError("Not an entity"); return nullptr; } + assert(entref.entnum < Game::MAX_GENTITIES); + return &Game::g_entities[entref.entnum]; } @@ -547,7 +566,7 @@ namespace Components void Script::AddFunctions() { - Script::AddFunction("ReplaceFunc", [](Game::scr_entref_t) // gsc: ReplaceFunc(, ) + Script::AddFunction("ReplaceFunc", []() // gsc: ReplaceFunc(, ) { if (Game::Scr_GetNumParam() != 2u) { @@ -562,7 +581,7 @@ namespace Components }); // System time - Script::AddFunction("GetSystemTime", [](Game::scr_entref_t) // gsc: GetSystemTime() + Script::AddFunction("GetSystemTime", []() // gsc: GetSystemTime() { SYSTEMTIME time; GetSystemTime(&time); @@ -570,7 +589,7 @@ namespace Components Game::Scr_AddInt(time.wSecond); }); - Script::AddFunction("GetSystemMilliseconds", [](Game::scr_entref_t) // gsc: GetSystemMilliseconds() + Script::AddFunction("GetSystemMilliseconds", []() // gsc: GetSystemMilliseconds() { SYSTEMTIME time; GetSystemTime(&time); @@ -579,7 +598,7 @@ namespace Components }); // Executes command to the console - Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec() + Script::AddFunction("Exec", []() // gsc: Exec() { const auto str = Game::Scr_GetString(0); @@ -593,7 +612,7 @@ namespace Components }); // Allow printing to the console even when developer is 0 - Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole() + Script::AddFunction("PrintConsole", []() // gsc: PrintConsole() { for (auto i = 0u; i < Game::Scr_GetNumParam(); i++) { @@ -610,7 +629,7 @@ namespace Components }); // Script Storage Funcs - Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(, ); + Script::AddFunction("StorageSet", []() // gsc: StorageSet(, ); { const auto* key = Game::Scr_GetString(0); const auto* value = Game::Scr_GetString(1); @@ -624,7 +643,7 @@ namespace Components Script::ScriptStorage.insert_or_assign(key, value); }); - Script::AddFunction("StorageRemove", [](Game::scr_entref_t) // gsc: StorageRemove(); + Script::AddFunction("StorageRemove", []() // gsc: StorageRemove(); { const auto* key = Game::Scr_GetString(0); @@ -643,7 +662,7 @@ namespace Components Script::ScriptStorage.erase(key); }); - Script::AddFunction("StorageGet", [](Game::scr_entref_t) // gsc: StorageGet(); + Script::AddFunction("StorageGet", []() // gsc: StorageGet(); { const auto* key = Game::Scr_GetString(0); @@ -663,7 +682,7 @@ namespace Components Game::Scr_AddString(data.data()); }); - Script::AddFunction("StorageHas", [](Game::scr_entref_t) // gsc: StorageHas(); + Script::AddFunction("StorageHas", []() // gsc: StorageHas(); { const auto* key = Game::Scr_GetString(0); @@ -676,13 +695,13 @@ namespace Components Game::Scr_AddBool(Script::ScriptStorage.count(key)); }); - Script::AddFunction("StorageClear", [](Game::scr_entref_t) // gsc: StorageClear(); + Script::AddFunction("StorageClear", []() // gsc: StorageClear(); { Script::ScriptStorage.clear(); }); // PlayerCmd_AreControlsFrozen GSC function from Black Ops 2 - Script::AddFunction("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); + Script::AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); { const auto* ent = Script::GetEntity(entref); @@ -718,8 +737,13 @@ namespace Components Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick(); Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick(); - Utils::Hook(0x44E736, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetFunction - Utils::Hook(0x4EC8E5, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetMethod + // Register custom functions + Utils::Hook(0x46577C, Script::Scr_GetFunctionStub, HOOK_CALL).install()->quick(); // Scr_BeginLoadScripts + Utils::Hook(0x465787, Script::Scr_GetMethodStub, HOOK_CALL).install()->quick(); // Scr_BeginLoadScripts + + // Fetch custom functions + Utils::Hook(0x44E72E, Script::BuiltIn_GetFunctionStub, HOOK_CALL).install()->quick(); // Scr_GetFunction + Utils::Hook(0x4EC88E, Script::Player_GetMethodStub, HOOK_CALL).install()->quick(); // Scr_GetMethod Utils::Hook(0x5F41A3, Script::SetExpFogStub, HOOK_CALL).install()->quick(); @@ -747,7 +771,7 @@ namespace Components Script::LastFrameTime = nowMs; }); - Script::AddFunction("DebugBox", [](Game::scr_entref_t) + Script::AddFunction("DebugBox", []() { const auto* message = Game::Scr_GetString(0); @@ -772,7 +796,10 @@ namespace Components Script::ScriptName.clear(); Script::ScriptHandles.clear(); Script::ScriptNameStack.clear(); - Script::ScriptFunctions.clear(); + + Script::CustomScrFunctions.clear(); + Script::CustomScrMethods.clear(); + Script::ReplacedFunctions.clear(); Script::VMShutdownSignal.clear(); diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index c1de5331..1d1144aa 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -6,26 +6,13 @@ namespace Components class Script : public Component { public: - class Function - { - public: - Function(const std::string& _name, Game::scr_function_t _callback, bool _dev) : name(_name), callback(_callback), dev(_dev) {} - - const char* getName() const { return this->name.data(); } - bool isDev() const { return this->dev; } - Game::scr_function_t getFunction() const { return this->callback; } - - private: - std::string name; - Game::scr_function_t callback; - bool dev; - }; - Script(); ~Script(); static int LoadScriptAndLabel(const std::string& script, const std::string& label); - static void AddFunction(const std::string& name, Game::scr_function_t function, bool isDev = false); + + static void AddFunction(const char* name, Game::xfunction_t func, int type = 0); + static void AddMethod(const char* name, Game::xmethod_t func, int type = 0); static void OnVMShutdown(Utils::Slot callback); @@ -35,7 +22,8 @@ namespace Components private: static std::string ScriptName; static std::vector ScriptHandles; - static std::vector ScriptFunctions; + static std::unordered_map CustomScrFunctions; + static std::unordered_map CustomScrMethods; static std::vector ScriptNameStack; static unsigned short FunctionName; static std::unordered_map ScriptStorage; @@ -62,8 +50,11 @@ namespace Components static void LoadGameType(); static void LoadGameTypeScript(); - static Game::scr_function_t GetFunction(void* caller, const char** name, int* isDev); - static void GetFunctionStub(); + static Game::xfunction_t Scr_GetFunctionStub(const char** pName, int* type); + static Game::xmethod_t Scr_GetMethodStub(const char** pName, int* type); + + static Game::xfunction_t BuiltIn_GetFunctionStub(const char** pName, int* type); + static Game::xmethod_t Player_GetMethodStub(const char** pName); static void ScrShutdownSystemStub(int); static void StoreScriptBaseProgramNumStub(); diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 1a852ae9..a6823ea8 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -8,7 +8,7 @@ namespace Components { //File functions - Script::AddFunction("FileWrite", [](Game::scr_entref_t) // gsc: FileWrite(, , ) + Script::AddFunction("FileWrite", []() // gsc: FileWrite(, , ) { const auto* path = Game::Scr_GetString(0); auto* text = Game::Scr_GetString(1); @@ -51,7 +51,7 @@ namespace Components } }); - Script::AddFunction("FileRead", [](Game::scr_entref_t) // gsc: FileRead() + Script::AddFunction("FileRead", []() // gsc: FileRead() { const auto* path = Game::Scr_GetString(0); @@ -79,7 +79,7 @@ namespace Components Game::Scr_AddString(FileSystem::FileReader(path).getBuffer().data()); }); - Script::AddFunction("FileExists", [](Game::scr_entref_t) // gsc: FileExists() + Script::AddFunction("FileExists", []() // gsc: FileExists() { const auto* path = Game::Scr_GetString(0); @@ -101,7 +101,7 @@ namespace Components Game::Scr_AddInt(FileSystem::FileReader(path).exists()); }); - Script::AddFunction("FileRemove", [](Game::scr_entref_t) // gsc: FileRemove() + Script::AddFunction("FileRemove", []() // gsc: FileRemove() { const auto* path = Game::Scr_GetString(0); @@ -130,7 +130,7 @@ namespace Components void ScriptExtension::AddMethods() { // ScriptExtension methods - Script::AddFunction("GetIp", [](Game::scr_entref_t entref) // gsc: self GetIp() + Script::AddMethod("GetIp", [](Game::scr_entref_t entref) // gsc: self GetIp() { const auto* gentity = Script::GetEntity(entref); const auto* client = Script::GetClient(gentity); @@ -145,7 +145,7 @@ namespace Components Game::Scr_AddString(ip.data()); }); - Script::AddFunction("GetPing", [](Game::scr_entref_t entref) // gsc: self GetPing() + Script::AddMethod("GetPing", [](Game::scr_entref_t entref) // gsc: self GetPing() { const auto* gentity = Script::GetEntity(entref); const auto* client = Script::GetClient(gentity); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index eea681a5..31926ec4 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -699,7 +699,7 @@ namespace Game typedef void(__cdecl * Scr_ClearOutParams_t)(); extern Scr_ClearOutParams_t Scr_ClearOutParams; - typedef void(__cdecl * Scr_RegisterFunction_t)(scr_function_t function); + typedef void(__cdecl * Scr_RegisterFunction_t)(int func, const char* name); extern Scr_RegisterFunction_t Scr_RegisterFunction; typedef bool(__cdecl * Scr_IsSystemActive_t)(); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 84792969..621523d2 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -26,7 +26,22 @@ namespace Game unsigned __int16 classnum; }; - typedef void(__cdecl * scr_function_t)(scr_entref_t); + typedef void(__cdecl * xfunction_t)(); + typedef void(__cdecl * xmethod_t)(scr_entref_t); + + struct BuiltinFunctionDef + { + const char* actionString; + xfunction_t actionFunc; + int type; + }; + + struct BuiltinMethodDef + { + const char* actionString; + xmethod_t actionFunc; + int type; + }; enum XAssetType { From 14662794343b991c19be0b0dc453eeed6bac58cb Mon Sep 17 00:00:00 2001 From: FutureRave Date: Fri, 25 Feb 2022 11:58:11 +0000 Subject: [PATCH 02/10] switch from bool to int --- src/Components/Modules/Script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 1266ff72..184d26c0 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -781,7 +781,7 @@ namespace Components } MessageBoxA(nullptr, message, "DEBUG", MB_OK); - }, true); + }, 1); Script::AddFunctions(); From 4156bacf2aa9a0b78bef21c4730cb6be472e90f7 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Fri, 25 Feb 2022 12:37:01 +0000 Subject: [PATCH 03/10] Use key from map when searching for custom func --- src/Components/Modules/Script.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 23aae4a2..e72021cd 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -295,7 +295,7 @@ namespace Components { for (const auto& [key, value] : Script::CustomScrFunctions) { - Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), value.actionString); + Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), key.data()); } return Utils::Hook::Call(0x44E700)(pName, type); // Scr_GetFunction @@ -305,7 +305,7 @@ namespace Components { for (const auto& [key, value] : Script::CustomScrMethods) { - Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), value.actionString); + Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), key.data()); } return Utils::Hook::Call(0x4EC870)(pName, type); // Scr_GetMethod @@ -315,7 +315,7 @@ namespace Components { if (pName && *pName) { - const auto got = Script::CustomScrFunctions.find(*pName); + const auto got = Script::CustomScrFunctions.find(Utils::String::ToLower(*pName)); // If no function was found let's call game's function if (got != Script::CustomScrFunctions.end()) @@ -332,7 +332,7 @@ namespace Components { if (pName && *pName) { - const auto got = Script::CustomScrMethods.find(*pName); + const auto got = Script::CustomScrMethods.find(Utils::String::ToLower(*pName)); // If no method was found let's call game's function if (got != Script::CustomScrMethods.end()) From f343b2da3fd2969dc9b6695e955cb34133b06826 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 9 Apr 2022 18:27:18 +0200 Subject: [PATCH 04/10] Add scr_toupper --- src/Components/Modules/ScriptExtension.cpp | 47 +++++++++++++++++++++- src/Game/Functions.cpp | 3 ++ src/Game/Functions.hpp | 17 ++++++-- src/Game/Structs.hpp | 2 + 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 1bc7a4b4..c6e42606 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -6,7 +6,7 @@ namespace Components void ScriptExtension::AddFunctions() { - //File functions + // File functions Script::AddFunction("FileWrite", []() // gsc: FileWrite(, , ) { const auto* path = Game::Scr_GetString(0); @@ -124,6 +124,51 @@ namespace Components const auto& file = p.filename().string(); Game::Scr_AddInt(FileSystem::DeleteFile(folder, file)); }); + + // Misc functions + Script::AddFunction("ToUpper", []() + { + const auto scriptValue = Game::Scr_GetConstString(0); + const auto* string = Game::SL_ConvertToString(scriptValue); + + char out[1024] = {0}; // 1024 is the max for a string in this SL system + bool changed = false; + + auto i = 0u; + while (i < sizeof(out)) + { + const auto value = *string; + const auto result = std::toupper(static_cast(value)); + out[i] = static_cast(result); + + if (value != result) + changed = true; + + if (result == '\0') // Finished converting string + break; + + ++string; + ++i; + } + + // Null terminating character was overwritten + if (i >= sizeof(out)) + { + Game::Scr_Error("string too long"); + return; + } + + if (changed) + { + Game::Scr_AddString(out); + } + else + { + Game::SL_AddRefToString(scriptValue); + Game::Scr_AddConstString(scriptValue); + Game::SL_RemoveRefToString(scriptValue); + } + }); } void ScriptExtension::AddMethods() diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 3e9171dd..0c1f1b91 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -272,6 +272,7 @@ namespace Game Scr_AddEntity_t Scr_AddEntity = Scr_AddEntity_t(0x4BFB40); Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310); + Scr_AddConstString_t Scr_AddConstString = Scr_AddConstString_t(0x488860); Scr_AddIString_t Scr_AddIString = Scr_AddIString_t(0x455F20); Scr_AddInt_t Scr_AddInt = Scr_AddInt_t(0x41D7D0); Scr_AddFloat_t Scr_AddFloat = Scr_AddFloat_t(0x61E860); @@ -313,6 +314,8 @@ namespace Game SL_ConvertToString_t SL_ConvertToString = SL_ConvertToString_t(0x4EC1D0); SL_GetString_t SL_GetString = SL_GetString_t(0x4CDC10); + SL_AddRefToString_t SL_AddRefToString = SL_AddRefToString_t(0x4D9B00); + SL_RemoveRefToString_t SL_RemoveRefToString = SL_RemoveRefToString_t(0x47CD70); SND_Init_t SND_Init = SND_Init_t(0x46A630); SND_InitDriver_t SND_InitDriver = SND_InitDriver_t(0x4F5090); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index a0fdd9d7..dc83c41e 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -645,6 +645,9 @@ namespace Game typedef void(__cdecl * Scr_AddString_t)(const char* value); extern Scr_AddString_t Scr_AddString; + typedef void(__cdecl * Scr_AddConstString_t)(unsigned int value); + extern Scr_AddConstString_t Scr_AddConstString; + typedef void(__cdecl * Scr_AddIString_t)(const char* value); extern Scr_AddIString_t Scr_AddIString; @@ -669,7 +672,7 @@ namespace Game typedef const char*(__cdecl * Scr_GetString_t)(unsigned int index); extern Scr_GetString_t Scr_GetString; - typedef unsigned int(__cdecl * Scr_GetConstString_t)(unsigned int index); + typedef scr_string_t(__cdecl * Scr_GetConstString_t)(unsigned int index); extern Scr_GetConstString_t Scr_GetConstString; typedef const char*(__cdecl * Scr_GetDebugString_t)(unsigned int index); @@ -738,21 +741,27 @@ namespace Game typedef int(__cdecl * Script_CleanString_t)(char* buffer); extern Script_CleanString_t Script_CleanString; - typedef char* (__cdecl * SE_Load_t)(const char* file, int Unk); + typedef char*(__cdecl * SE_Load_t)(const char* file, int Unk); extern SE_Load_t SE_Load; - typedef char* (__cdecl * SEH_StringEd_GetString_t)(const char* string); + typedef char*(__cdecl * SEH_StringEd_GetString_t)(const char* string); extern SEH_StringEd_GetString_t SEH_StringEd_GetString; typedef unsigned int(__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); extern SEH_ReadCharFromString_t SEH_ReadCharFromString; - typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue); + typedef char*(__cdecl * SL_ConvertToString_t)(unsigned short stringValue); extern SL_ConvertToString_t SL_ConvertToString; typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user); extern SL_GetString_t SL_GetString; + typedef void(__cdecl * SL_AddRefToString_t)(unsigned int stringValue); + extern SL_AddRefToString_t SL_AddRefToString; + + typedef void(__cdecl * SL_RemoveRefToString_t)(unsigned int stringValue); + extern SL_RemoveRefToString_t SL_RemoveRefToString; + typedef void(__cdecl * SND_Init_t)(int a1, int a2, int a3); extern SND_Init_t SND_Init; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 5ac250c9..8c4e9523 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -20,6 +20,8 @@ namespace Game typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; + typedef unsigned __int16 scr_string_t; + struct scr_entref_t { unsigned __int16 entnum; From 25a84bdb0ad359aa8cb8c5de60b85dcb5a5a7150 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 9 Apr 2022 20:49:35 +0200 Subject: [PATCH 05/10] Reorder the static_cast(s) --- src/Components/Modules/ScriptExtension.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index c6e42606..7c0ed851 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -138,8 +138,8 @@ namespace Components while (i < sizeof(out)) { const auto value = *string; - const auto result = std::toupper(static_cast(value)); - out[i] = static_cast(result); + const auto result = static_cast(std::toupper(static_cast(value))); + out[i] = result; if (value != result) changed = true; From 79d4aca33ddc65fa85bdb048e9823eee09b8d022 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 10 Apr 2022 14:00:55 +0200 Subject: [PATCH 06/10] Add some more utils funcs --- src/Components/Modules/Script.cpp | 49 +++++++++------------- src/Components/Modules/Script.hpp | 5 +-- src/Components/Modules/ScriptExtension.cpp | 29 ++++++++++++- src/Utils/String.cpp | 5 ++- src/Utils/String.hpp | 4 +- 5 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index d7ddc546..292ca51d 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -292,29 +292,9 @@ namespace Components CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); } - Game::xfunction_t Script::Scr_GetFunctionStub(const char** pName, int* type) - { - for (const auto& [key, value] : Script::CustomScrFunctions) - { - Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), key.data()); - } - - return Utils::Hook::Call(0x44E700)(pName, type); // Scr_GetFunction - } - - Game::xmethod_t Script::Scr_GetMethodStub(const char** pName, int* type) - { - for (const auto& [key, value] : Script::CustomScrMethods) - { - Game::Scr_RegisterFunction(reinterpret_cast(value.actionFunc), key.data()); - } - - return Utils::Hook::Call(0x4EC870)(pName, type); // Scr_GetMethod - } - Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type) { - if (pName && *pName) + if (pName) { const auto got = Script::CustomScrFunctions.find(Utils::String::ToLower(*pName)); @@ -325,24 +305,39 @@ namespace Components return got->second.actionFunc; } } + else + { + for (const auto& [name, builtin] : Script::CustomScrFunctions) + { + Game::Scr_RegisterFunction(reinterpret_cast(builtin.actionFunc), name.data()); + } + } return Utils::Hook::Call(0x5FA2B0)(pName, type); // BuiltIn_GetFunction } - Game::xmethod_t Script::Player_GetMethodStub(const char** pName) + Game::xmethod_t Script::BuiltIn_GetMethod(const char** pName, int* type) { - if (pName && *pName) + if (pName) { const auto got = Script::CustomScrMethods.find(Utils::String::ToLower(*pName)); // If no method was found let's call game's function if (got != Script::CustomScrMethods.end()) { + *type = got->second.type; return got->second.actionFunc; } } + else + { + for (const auto& [name, builtin] : Script::CustomScrMethods) + { + Game::Scr_RegisterFunction(reinterpret_cast(builtin.actionFunc), name.data()); + } + } - return Utils::Hook::Call(0x4C07D0)(pName); // Player_GetMethod + return Utils::Hook::Call(0x5FA360)(pName, type); // Player_GetMethod } void Script::StoreScriptBaseProgramNum() @@ -721,13 +716,9 @@ namespace Components Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick(); Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick(); - // Register custom functions - Utils::Hook(0x46577C, Script::Scr_GetFunctionStub, HOOK_CALL).install()->quick(); // Scr_BeginLoadScripts - Utils::Hook(0x465787, Script::Scr_GetMethodStub, HOOK_CALL).install()->quick(); // Scr_BeginLoadScripts - // Fetch custom functions Utils::Hook(0x44E72E, Script::BuiltIn_GetFunctionStub, HOOK_CALL).install()->quick(); // Scr_GetFunction - Utils::Hook(0x4EC88E, Script::Player_GetMethodStub, HOOK_CALL).install()->quick(); // Scr_GetMethod + Utils::Hook(0x4EC8DD, Script::BuiltIn_GetMethod, HOOK_CALL).install()->quick(); // Scr_GetMethod Utils::Hook(0x5F41A3, Script::SetExpFogStub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index 457879e5..09a63c22 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -49,11 +49,8 @@ namespace Components static void LoadGameType(); static void LoadGameTypeScript(); - static Game::xfunction_t Scr_GetFunctionStub(const char** pName, int* type); - static Game::xmethod_t Scr_GetMethodStub(const char** pName, int* type); - static Game::xfunction_t BuiltIn_GetFunctionStub(const char** pName, int* type); - static Game::xmethod_t Player_GetMethodStub(const char** pName); + static Game::xmethod_t BuiltIn_GetMethod(const char** pName, int* type); static void ScrShutdownSystemStub(unsigned char sys); static void StoreScriptBaseProgramNumStub(); diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 7c0ed851..e156a5d0 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -126,7 +126,7 @@ namespace Components }); // Misc functions - Script::AddFunction("ToUpper", []() + Script::AddFunction("ToUpper", []() // gsc: ToUpper() { const auto scriptValue = Game::Scr_GetConstString(0); const auto* string = Game::SL_ConvertToString(scriptValue); @@ -169,6 +169,33 @@ namespace Components Game::SL_RemoveRefToString(scriptValue); } }); + + // Func present on IW5 + Script::AddFunction("StrICmp", []() // gsc: StrICmp(, ) + { + const auto value1 = Game::Scr_GetConstString(0); + const auto value2 = Game::Scr_GetConstString(1); + + const auto result = std::strcmp(Game::SL_ConvertToString(value1), + Game::SL_ConvertToString(value2)); + + Game::Scr_AddInt(result); + }); + + // Func present on IW5 + Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(, ) + { + const auto* s1 = Game::Scr_GetString(0); + const auto* s2 = Game::Scr_GetString(0); + + if (s1 == nullptr || s2 == nullptr) + { + Game::Scr_Error("^1IsEndStr: Illegal parameters!\n"); + return; + } + + Game::Scr_AddBool(Utils::String::EndsWith(s1, s2)); + }); } void ScriptExtension::AddMethods() diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 422a9158..3927e48e 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -89,12 +89,13 @@ namespace Utils bool StartsWith(const std::string& haystack, const std::string& needle) { - return (haystack.size() >= needle.size() && haystack.substr(0, needle.size()) == needle); + return haystack.find(needle) == 0; // If the pos of the first found char is 0, string starts with 'needle' } bool EndsWith(const std::string& haystack, const std::string& needle) { - return (haystack.size() >= needle.size() && haystack.substr(haystack.size() - needle.size()) == needle); + if (needle.size() > haystack.size()) return false; + return std::equal(needle.rbegin(), needle.rend(), haystack.rbegin()); } int IsSpace(int c) diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index bd99e73a..8b2b12aa 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -77,10 +77,10 @@ namespace Utils int IsSpace(int c); std::string ToLower(std::string input); std::string ToUpper(std::string input); - bool EndsWith(const std::string& haystack, const std::string& needle); - std::vector Split(const std::string& str, const char delim); void Replace(std::string& string, const std::string& find, const std::string& replace); + bool EndsWith(const std::string& haystack, const std::string& needle); bool StartsWith(const std::string& haystack, const std::string& needle); + std::vector Split(const std::string& str, const char delim); std::string& LTrim(std::string& str); std::string& RTrim(std::string& str); From d18a576ba27ae2ee8ed23c957cdd8fcdad9ed97b Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 10 Apr 2022 14:13:32 +0200 Subject: [PATCH 07/10] Address some warnings --- src/Components/Modules/Script.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 292ca51d..6aa19501 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -140,11 +140,9 @@ namespace Components std::string buffer = script.getBuffer(); Utils::String::Replace(buffer, "\t", " "); - int line = 1; - int lineOffset = 0; - int inlineOffset = 0; + auto line = 1, lineOffset = 0, inlineOffset = 0; - for (unsigned int i = 0; i < buffer.size(); ++i) + for (size_t i = 0; i < buffer.size(); ++i) { // Terminate line if (i == offset) @@ -161,7 +159,7 @@ namespace Components if (buffer[i] == '\n') { ++line; - lineOffset = i; // Includes the line break! + lineOffset = static_cast(i); // Includes the line break! inlineOffset = 0; } else @@ -173,7 +171,7 @@ namespace Components Logger::Print(23, "in file %s, line %d:", filename, line); Logger::Print(23, "%s\n", buffer.data() + lineOffset); - for (int i = 0; i < (inlineOffset - 1); ++i) + for (auto i = 0; i < (inlineOffset - 1); ++i) { Logger::Print(23, " "); } @@ -249,7 +247,7 @@ namespace Components for (auto file : list) { - file = "scripts/" + file; + file.insert(0, "scripts/"); if (Utils::String::EndsWith(file, ".gsc")) { @@ -294,7 +292,7 @@ namespace Components Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type) { - if (pName) + if (pName != nullptr) { const auto got = Script::CustomScrFunctions.find(Utils::String::ToLower(*pName)); @@ -318,7 +316,7 @@ namespace Components Game::xmethod_t Script::BuiltIn_GetMethod(const char** pName, int* type) { - if (pName) + if (pName != nullptr) { const auto got = Script::CustomScrMethods.find(Utils::String::ToLower(*pName)); From 0f1c2c0195097fe8c9ae1468faae5b1adf87e2b4 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 10 Apr 2022 14:37:04 +0200 Subject: [PATCH 08/10] Oops moment --- src/Components/Modules/ScriptExtension.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index e156a5d0..086d3a7a 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -186,7 +186,7 @@ namespace Components Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(, ) { const auto* s1 = Game::Scr_GetString(0); - const auto* s2 = Game::Scr_GetString(0); + const auto* s2 = Game::Scr_GetString(1); if (s1 == nullptr || s2 == nullptr) { From 17059c9ca306c63ab7e540daf5dffb1e8101c7f8 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 10 Apr 2022 15:02:25 +0200 Subject: [PATCH 09/10] Case insentive comparison like the game does :/ --- src/Components/Modules/ScriptExtension.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 086d3a7a..b2c7a526 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -134,7 +134,7 @@ namespace Components char out[1024] = {0}; // 1024 is the max for a string in this SL system bool changed = false; - auto i = 0u; + size_t i = 0; while (i < sizeof(out)) { const auto value = *string; @@ -176,7 +176,7 @@ namespace Components const auto value1 = Game::Scr_GetConstString(0); const auto value2 = Game::Scr_GetConstString(1); - const auto result = std::strcmp(Game::SL_ConvertToString(value1), + const auto result = _stricmp(Game::SL_ConvertToString(value1), Game::SL_ConvertToString(value2)); Game::Scr_AddInt(result); From bd19102eb7d0ccaed312951f8da42c6ee30208c9 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 10 Apr 2022 15:12:01 +0200 Subject: [PATCH 10/10] FIx header --- src/Utils/String.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 11c9130a..51012e8a 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -77,12 +77,10 @@ namespace Utils int IsSpace(int c); std::string ToLower(std::string text); std::string ToUpper(std::string text); - bool EndsWith(const std::string& haystack, const std::string& needle); std::vector Split(const std::string& str, const char delim); void Replace(std::string& string, const std::string& find, const std::string& replace); - bool EndsWith(const std::string& haystack, const std::string& needle); bool StartsWith(const std::string& haystack, const std::string& needle); - std::vector Split(const std::string& str, const char delim); + bool EndsWith(const std::string& haystack, const std::string& needle); std::string& LTrim(std::string& str); std::string& RTrim(std::string& str);