From 3246ed1bf515e3b2b6818845cb4d79c149a7a786 Mon Sep 17 00:00:00 2001 From: Edo Date: Tue, 23 Aug 2022 09:12:20 +0200 Subject: [PATCH] [Script] Refactor loading code & add pseudo int64 (#419) --- src/Components/Modules/Console.cpp | 4 +- src/Components/Modules/Console.hpp | 2 +- src/Components/Modules/FileSystem.cpp | 16 ++--- src/Components/Modules/GSC/GSC.cpp | 2 + src/Components/Modules/GSC/Int64.cpp | 95 +++++++++++++++++++++++++++ src/Components/Modules/GSC/Int64.hpp | 20 ++++++ src/Components/Modules/GSC/Script.cpp | 37 ++++++----- src/Components/Modules/Zones.cpp | 7 +- src/Game/Functions.cpp | 22 +------ src/Game/Functions.hpp | 12 ++-- 10 files changed, 158 insertions(+), 59 deletions(-) create mode 100644 src/Components/Modules/GSC/Int64.cpp create mode 100644 src/Components/Modules/GSC/Int64.hpp diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index bcb5995d..8d81683b 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -24,10 +24,10 @@ namespace Components Game::SafeArea Console::OriginalSafeArea; - char** Console::GetAutoCompleteFileList(const char* path, const char* extension, Game::FsListBehavior_e behavior, int* numfiles, int allocTrackType) + const char** Console::GetAutoCompleteFileList(const char* path, const char* extension, Game::FsListBehavior_e behavior, int* numfiles, int allocTrackType) { if (path == reinterpret_cast(0xBAADF00D) || path == reinterpret_cast(0xCDCDCDCD) || ::Utils::Memory::IsBadReadPtr(path)) return nullptr; - return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType); + return Game::FS_ListFiles(path, extension, behavior, numfiles, allocTrackType); } void Console::RefreshStatus() diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index 774631bd..f7aa6e7b 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -63,7 +63,7 @@ namespace Components static void StoreSafeArea(); static void RestoreSafeArea(); - static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); + static const char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); static void Con_ToggleConsole(); static void AddConsoleCommand(); diff --git a/src/Components/Modules/FileSystem.cpp b/src/Components/Modules/FileSystem.cpp index 641714f9..473a38ac 100644 --- a/src/Components/Modules/FileSystem.cpp +++ b/src/Components/Modules/FileSystem.cpp @@ -160,8 +160,8 @@ namespace Components { std::vector fileList; - int numFiles = 0; - char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0); + auto numFiles = 0; + const auto** files = Game::FS_ListFiles(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 10); if (files) { @@ -169,11 +169,11 @@ namespace Components { if (files[i]) { - fileList.push_back(files[i]); + fileList.emplace_back(files[i]); } } - Game::FS_FreeFileList(files); + Game::FS_FreeFileList(files, 10); } return fileList; @@ -183,8 +183,8 @@ namespace Components { std::vector fileList; - int numFiles = 0; - char** files = Game::Sys_ListFiles(path.data(), extension.data(), nullptr, &numFiles, folders); + auto numFiles = 0; + const auto** files = Game::Sys_ListFiles(path.data(), extension.data(), nullptr, &numFiles, folders); if (files) { @@ -192,7 +192,7 @@ namespace Components { if (files[i]) { - fileList.push_back(files[i]); + fileList.emplace_back(files[i]); } } @@ -204,7 +204,7 @@ namespace Components bool FileSystem::_DeleteFile(const std::string& folder, const std::string& file) { - char path[MAX_PATH] = { 0 }; + char path[MAX_PATH] = {0}; Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").get(), reinterpret_cast(0x63D0BB8), Utils::String::VA("%s/%s", folder.data(), file.data()), reinterpret_cast(&path)); return Game::FS_Remove(path); } diff --git a/src/Components/Modules/GSC/GSC.cpp b/src/Components/Modules/GSC/GSC.cpp index 18de80a4..3970b014 100644 --- a/src/Components/Modules/GSC/GSC.cpp +++ b/src/Components/Modules/GSC/GSC.cpp @@ -1,5 +1,6 @@ #include +#include "Int64.hpp" #include "IO.hpp" #include "Script.hpp" #include "ScriptExtension.hpp" @@ -9,6 +10,7 @@ namespace Components { GSC::GSC() { + Loader::Register(new Int64()); Loader::Register(new IO()); Loader::Register(new Script()); Loader::Register(new ScriptExtension()); diff --git a/src/Components/Modules/GSC/Int64.cpp b/src/Components/Modules/GSC/Int64.cpp new file mode 100644 index 00000000..c2fc4eee --- /dev/null +++ b/src/Components/Modules/GSC/Int64.cpp @@ -0,0 +1,95 @@ +#include +#include "Int64.hpp" +#include "Script.hpp" + +#define INT64_OPERATION(expr) [](const std::int64_t a, [[maybe_unused]] const std::int64_t b) { return expr; } + +namespace Components +{ + std::unordered_map Int64::Operations = + { + {"+", INT64_OPERATION(a + b)}, + {"-", INT64_OPERATION(a - b)}, + {"*", INT64_OPERATION(a * b)}, + {"/", INT64_OPERATION(a / b)}, + {"&", INT64_OPERATION(a & b)}, + {"^", INT64_OPERATION(a ^ b)}, + {"|", INT64_OPERATION(a | b)}, + {"~", INT64_OPERATION(~a)}, + {"%", INT64_OPERATION(a % b)}, + {">>", INT64_OPERATION(a >> b)}, + {"<<", INT64_OPERATION(a << b)}, + {"++", INT64_OPERATION(a + 1)}, + {"--", INT64_OPERATION(a - 1)}, + }; + + std::unordered_map Int64::Comparisons + { + {">", INT64_OPERATION(a > b)}, + {">=", INT64_OPERATION(a >= b)}, + {"==", INT64_OPERATION(a == b)}, + {"<=", INT64_OPERATION(a <= b)}, + {"<", INT64_OPERATION(a < b)}, + }; + + std::int64_t Int64::GetInt64Arg(unsigned int index, bool optional) + { + if ((optional) && (index >= Game::Scr_GetNumParam())) + { + return 0; + } + + if (Game::Scr_GetType(index) == Game::VAR_INTEGER) + { + return Game::Scr_GetInt(index); + } + + if (Game::Scr_GetType(index) == Game::VAR_STRING) + { + return std::strtoll(Game::Scr_GetString(index), nullptr, 0); + } + + Game::Scr_ParamError(index, Utils::String::VA("cannot cast %s to int64", Game::Scr_GetTypeName(index))); + return 0; + } + + void Int64::AddFunctions() + { + Script::AddFunction("Int64IsInt", [] + { + const auto value = GetInt64Arg(0, false); + Game::Scr_AddBool(value <= std::numeric_limits::max() && value >= std::numeric_limits::min()); + }); + + Script::AddFunction("Int64ToInt", [] + { + Game::Scr_AddInt(static_cast(GetInt64Arg(0, false))); + }); + + Script::AddFunction("Int64OP", [] + { + const auto a = GetInt64Arg(0, false); + const auto* op = Game::Scr_GetString(1); + const auto b = GetInt64Arg(2, true); + + if (const auto got = Operations.find(op); got != Operations.end()) + { + Game::Scr_AddString(Utils::String::VA("%lld", got->second(a, b))); + return; + } + + if (const auto got = Comparisons.find(op); got != Comparisons.end()) + { + Game::Scr_AddBool(got->second(a, b)); + return; + } + + Game::Scr_ParamError(1, "Invalid int64 operation"); + }); + } + + Int64::Int64() + { + AddFunctions(); + } +} diff --git a/src/Components/Modules/GSC/Int64.hpp b/src/Components/Modules/GSC/Int64.hpp new file mode 100644 index 00000000..cbdc79f5 --- /dev/null +++ b/src/Components/Modules/GSC/Int64.hpp @@ -0,0 +1,20 @@ +#pragma once + +namespace Components +{ + class Int64 : public Component + { + public: + Int64(); + + private: + using int64_OP = std::function; + using int64_Comp = std::function; + + static std::unordered_map Operations; + static std::unordered_map Comparisons; + + static std::int64_t GetInt64Arg(unsigned int index, bool optional); + static void AddFunctions(); + }; +} diff --git a/src/Components/Modules/GSC/Script.cpp b/src/Components/Modules/GSC/Script.cpp index ee3a1595..b87c9b17 100644 --- a/src/Components/Modules/GSC/Script.cpp +++ b/src/Components/Modules/GSC/Script.cpp @@ -225,42 +225,44 @@ namespace Components Game::Scr_StartupGameType(); } + // Do not use C++ objects because Scr_LoadScript may longjmp void Script::GScr_LoadGameTypeScript_Stub() { // Clear handles (from previous GSC loading session) Script::ScriptMainHandles.clear(); Script::ScriptInitHandles.clear(); - const auto list = FileSystem::GetFileList("scripts/", "gsc"); + char path[MAX_PATH]{}; - for (const auto& file : list) + auto numFiles = 0; + const auto** files = Game::FS_ListFiles("scripts/", "gsc", Game::FS_LIST_ALL, &numFiles, 10); + + for (auto i = 0; i < numFiles; ++i) { - std::string script = "scripts/" + file; + const auto* scriptFile = files[i]; + Logger::Print("Loading script {}...\n", scriptFile); - if (Utils::String::EndsWith(script, ".gsc")) + sprintf_s(path, "%s/%s", "scripts", scriptFile); + + // Scr_LoadScriptInternal will add the '.gsc' suffix so we remove it + path[std::strlen(path) - 4] = '\0'; + + if (!Game::Scr_LoadScript(path)) { - script = script.substr(0, script.size() - 4); + Logger::Print("Script {} encountered an error while loading. (doesn't exist?)", path); + continue; } - Logger::Print("Loading script {}.gsc...\n", script); - - if (!Game::Scr_LoadScript(script.data())) - { - Logger::Print("Script {} encountered an error while loading. (doesn't exist?)", script); - Logger::Error(Game::ERR_DROP, "Could not find script '{}'", script); - return; - } - - Logger::Print("Script {}.gsc loaded successfully.\n", script); + Logger::Print("Script {}.gsc loaded successfully.\n", path); Logger::Debug("Finding script handle main or init..."); - const auto initHandle = Game::Scr_GetFunctionHandle(script.data(), "init"); + const auto initHandle = Game::Scr_GetFunctionHandle(path, "init"); if (initHandle != 0) { Script::ScriptInitHandles.push_back(initHandle); } - const auto mainHandle = Game::Scr_GetFunctionHandle(script.data(), "main"); + const auto mainHandle = Game::Scr_GetFunctionHandle(path, "main"); if (mainHandle != 0) { Script::ScriptMainHandles.push_back(mainHandle); @@ -269,6 +271,7 @@ namespace Components // Allow scripts with no handles } + Game::FS_FreeFileList(files, 10); Game::GScr_LoadGameTypeScript(); } diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index edcada03..e59c73cd 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -3483,14 +3483,14 @@ namespace Components Command::Add("decryptImages", [](Command::Params*) { - auto images = Game::Sys_ListFilesWrapper("iw4x/images", "iwi"); + auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); Logger::Print("decrypting {} images...\n", images.size()); for (auto& image : images) { char* buffer = nullptr; auto fileLength = Game::FS_ReadFile(Utils::String::VA("images/%s", image.data()), &buffer); - + if (fileLength && buffer) { if (!std::filesystem::exists("raw/images")) @@ -3514,9 +3514,10 @@ namespace Components Logger::Print("decrypted {} images!\n", images.size()); }); + Command::Add("decryptSounds", [](Command::Params*) { - auto sounds = Game::Sys_ListFilesWrapper("iw4x/sound", "iwi"); + auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi"); Logger::Print("decrypting {} sounds...\n", sounds.size()); for (auto& sound : sounds) diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index b4bb0d22..01addfd7 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -2,26 +2,6 @@ namespace Game { - std::vector Sys_ListFilesWrapper(const std::string& directory, const std::string& extension) - { - auto fileCount = 0; - auto** const files = Sys_ListFiles(directory.data(), extension.data(), nullptr, &fileCount, 0); - - std::vector result; - - for (auto i = 0; i < fileCount; i++) - { - if (files[i] != nullptr) - { - result.emplace_back(files[i]); - } - } - - FS_FreeFileList(files); - - return result; - } - AddRefToObject_t AddRefToObject = AddRefToObject_t(0x61C360); AllocObject_t AllocObject = AllocObject_t(0x434320); AddRefToValue_t AddRefToValue = AddRefToValue_t(0x482740); @@ -150,7 +130,7 @@ namespace Game FS_FileExists_t FS_FileExists = FS_FileExists_t(0x4DEFA0); FS_FreeFile_t FS_FreeFile = FS_FreeFile_t(0x4416B0); FS_ReadFile_t FS_ReadFile = FS_ReadFile_t(0x4F4B90); - FS_GetFileList_t FS_GetFileList = FS_GetFileList_t(0x441BB0); + FS_ListFiles_t FS_ListFiles = FS_ListFiles_t(0x441BB0); FS_FreeFileList_t FS_FreeFileList = FS_FreeFileList_t(0x4A5DE0); FS_FOpenFileAppend_t FS_FOpenFileAppend = FS_FOpenFileAppend_t(0x410BB0); FS_FOpenFileAppend_t FS_FOpenFileWrite = FS_FOpenFileAppend_t(0x4BA530); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 87766031..ef5542bb 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -20,8 +20,6 @@ namespace Game return retval; } - std::vector Sys_ListFilesWrapper(const std::string& directory, const std::string& extension); - typedef void(__cdecl * AddRefToObject_t)(unsigned int id); extern AddRefToObject_t AddRefToObject; @@ -376,10 +374,10 @@ namespace Game typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer); extern FS_ReadFile_t FS_ReadFile; - typedef char** (__cdecl * FS_GetFileList_t)(const char *path, const char *extension, FsListBehavior_e behavior, int *numfiles, int allocTrackType); - extern FS_GetFileList_t FS_GetFileList; + typedef const char**(__cdecl * FS_ListFiles_t)(const char* path, const char* extension, FsListBehavior_e behavior, int* numfiles, int allocTrackType); + extern FS_ListFiles_t FS_ListFiles; - typedef void(__cdecl * FS_FreeFileList_t)(char** list); + typedef void(__cdecl * FS_FreeFileList_t)(const char** list, int allocTrackType); extern FS_FreeFileList_t FS_FreeFileList; typedef int(__cdecl * FS_FOpenFileAppend_t)(const char* file); @@ -978,7 +976,7 @@ namespace Game typedef void(__cdecl * Sys_Error_t)(const char* error, ...); extern Sys_Error_t Sys_Error; - typedef void(__cdecl * Sys_FreeFileList_t)(char** list); + typedef void(__cdecl * Sys_FreeFileList_t)(const char** list); extern Sys_FreeFileList_t Sys_FreeFileList; typedef int(__cdecl * Sys_IsDatabaseReady_t)(); @@ -999,7 +997,7 @@ namespace Game typedef bool(__cdecl * Sys_IsDatabaseThread_t)(); extern Sys_IsDatabaseThread_t Sys_IsDatabaseThread; - typedef char**(__cdecl * Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs); + typedef const char**(__cdecl * Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs); extern Sys_ListFiles_t Sys_ListFiles; typedef int(__cdecl * Sys_Milliseconds_t)();