diff --git a/deps/red4ext.sdk b/deps/red4ext.sdk index 99ba88ab..a4c529d3 160000 --- a/deps/red4ext.sdk +++ b/deps/red4ext.sdk @@ -1 +1 @@ -Subproject commit 99ba88ab9749bffac5d0d27185390be016e0222d +Subproject commit a4c529d34ea63f32398db8903e0d3a5217a86a8c diff --git a/scripts/patterns.py b/scripts/patterns.py index 8cebb7b6..3bee9c20 100644 --- a/scripts/patterns.py +++ b/scripts/patterns.py @@ -28,7 +28,6 @@ def get_groups() -> List[Group]: return [ Group(name='Global', functions=[ Item(name='Main', pattern='40 53 48 81 EC ? ? ? ? FF 15 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ?', expected=1, index=0), - Item(name='ExecuteProcess', pattern='48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8', expected=1, index=0), ]), Group(name='CGameApplication', functions=[ @@ -46,7 +45,11 @@ def get_groups() -> List[Group]: Group(name='CShutdownState', functions=[ Item(name='Run', pattern='48 89 6C 24 18 56 48 83 EC 30 48 8B 0D ? ? ? ?', expected=1, index=0) ]), - + + Group(name='RedProcess', functions=[ + Item(name='Execute', pattern='48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8', expected=1, index=0), + ]), + Group(name='CBaseEngine', function=[ Item(name='InitScripts', pattern='48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 41 0F B7 D8 0F B6 FA 48 8B F1 E8', expected=1, index=0), Item(name='LoadScripts', pattern='48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 83 EC 20 49 8B F9 41 C6 81', expected=1, index=0) diff --git a/src/dll/Addresses.hpp b/src/dll/Addresses.hpp index 25819e9a..8a714647 100644 --- a/src/dll/Addresses.hpp +++ b/src/dll/Addresses.hpp @@ -31,7 +31,10 @@ constexpr uintptr_t CShutdownState_Run = 0x140A82390 - ImageBase; // 48 89 6C 24 #pragma region Global constexpr uintptr_t Global_Main = 0x1401A0330 - ImageBase; // 40 53 48 81 EC ? ? ? ? FF 15 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ?, expected: 1, index: 0 -constexpr uintptr_t Global_ExecuteProcess = 0x2C23D70; // 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8, expected: 1, index: 0 +#pragma endregion + +#pragma region RedProcess +constexpr uintptr_t RedProcess_Execute = 0x2C23D70; // 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8, expected: 1, index: 0 #pragma endregion #pragma region CBaseEngine diff --git a/src/dll/Hooks/ExecuteProcess.cpp b/src/dll/Hooks/ExecuteProcess.cpp index 29f605b1..f56c547d 100644 --- a/src/dll/Hooks/ExecuteProcess.cpp +++ b/src/dll/Hooks/ExecuteProcess.cpp @@ -7,35 +7,83 @@ namespace { bool isAttached = false; +uint32_t runCount = 0; -bool _Global_ExecuteProcess(void* a1, RED4ext::CString& aCommand, FixedWString& aArgs, - RED4ext::CString& aCurrentDirectory, char a5); -Hook Global_ExecuteProcess(Addresses::Global_ExecuteProcess, - &_Global_ExecuteProcess); +bool _RedProcess_Execute(RED4ext::Process* aThis, RED4ext::CString& aCommand, + RED4ext::Process::FixedWString& aArgs, RED4ext::CString& aCurrentDirectory, + RED4ext::Process::ExecutionFlags aFlags); +Hook RedProcess_Execute(Addresses::RedProcess_Execute, + &_RedProcess_Execute); -bool _Global_ExecuteProcess(void* a1, RED4ext::CString& aCommand, FixedWString& aArgs, - RED4ext::CString& aCurrentDirectory, char a5) +bool _RedProcess_Execute(RED4ext::Process* aThis, RED4ext::CString& aCommand, + RED4ext::Process::FixedWString& aArgs, RED4ext::CString& aCurrentDirectory, + RED4ext::Process::ExecutionFlags aFlags) { if (strstr(aCommand.c_str(), "scc.exe") == nullptr) { - return Global_ExecuteProcess(a1, aCommand, aArgs, aCurrentDirectory, a5); + return RedProcess_Execute(aThis, aCommand, aArgs, aCurrentDirectory, aFlags); } auto scriptCompilationSystem = App::Get()->GetScriptCompilationSystem(); - - FixedWString newArgs; - newArgs.str = scriptCompilationSystem->GetCompilationArgs(aArgs).c_str(); + auto str = scriptCompilationSystem->GetCompilationArgs(aArgs); + + RED4ext::Process::FixedWString newArgs; + newArgs.str = str.c_str(); newArgs.length = newArgs.maxLength = wcslen(newArgs.str); - return Global_ExecuteProcess(a1, aCommand, newArgs, aCurrentDirectory, a5); + + spdlog::info(L"Final redscript compilation arg string: '{}'", newArgs.str); + auto result = RedProcess_Execute(aThis, aCommand, newArgs, aCurrentDirectory, aFlags); + + auto waitResult = WaitForSingleObject(aThis->handle, RED4ext::Process::DefaultTimeout); + switch (waitResult) + { + case WAIT_TIMEOUT: + { + spdlog::error("Redscript compilation timed-out - exiting"); + SHOW_LAST_ERROR_MESSAGE_AND_EXIT_FILE_LINE("Redscript compilation timed-out"); + break; + } + case WAIT_ABANDONED: + { + spdlog::error("Redscript compilation was abandoned - exiting"); + SHOW_LAST_ERROR_MESSAGE_AND_EXIT_FILE_LINE("Redscript compilation was abandoned"); + break; + } + case WAIT_FAILED: + { + spdlog::error("Redscript compilation failed - exiting"); + SHOW_LAST_ERROR_MESSAGE_AND_EXIT_FILE_LINE("Redscript compilation failed"); + break; + } + } + + GetExitCodeProcess(aThis->handle, &aThis->errorCode); + + if (aThis->errorCode) + { + spdlog::error(L"Redscript compilation was unsuccessful with error code: {} - exiting", aThis->errorCode); + // redscript already showed the error, so we can just exit + if (scriptCompilationSystem->HasScripts() && runCount == 0) { + TerminateProcess(GetCurrentProcess(), 1); + } + } + else + { + spdlog::info(L"Redscript compilation executed successfully"); + } + + runCount++; + + return result; } } // namespace bool Hooks::ExecuteProcess::Attach() { spdlog::trace("Trying to attach the hook for execute process at {}...", - RED4EXT_OFFSET_TO_ADDR(Addresses::Global_ExecuteProcess)); + RED4EXT_OFFSET_TO_ADDR(Addresses::RedProcess_Execute)); - auto result = Global_ExecuteProcess.Attach(); + auto result = RedProcess_Execute.Attach(); if (result != NO_ERROR) { spdlog::error("Could not attach the hook for execute process. Detour error code: {}", result); @@ -57,9 +105,9 @@ bool Hooks::ExecuteProcess::Detach() } spdlog::trace("Trying to detach the hook for execute process at {}...", - RED4EXT_OFFSET_TO_ADDR(Addresses::Global_ExecuteProcess)); + RED4EXT_OFFSET_TO_ADDR(Addresses::RedProcess_Execute)); - auto result = Global_ExecuteProcess.Detach(); + auto result = RedProcess_Execute.Detach(); if (result != NO_ERROR) { spdlog::error("Could not detach the hook for execute process. Detour error code: {}", result); diff --git a/src/dll/Systems/ScriptCompilationSystem.cpp b/src/dll/Systems/ScriptCompilationSystem.cpp index 202eeb1e..cadaaba6 100644 --- a/src/dll/Systems/ScriptCompilationSystem.cpp +++ b/src/dll/Systems/ScriptCompilationSystem.cpp @@ -72,7 +72,7 @@ bool ScriptCompilationSystem::Add(std::shared_ptr aPlugin, const wch } } -std::wstring ScriptCompilationSystem::GetCompilationArgs(const FixedWString& aOriginal) +std::wstring ScriptCompilationSystem::GetCompilationArgs(const RED4ext::Process::FixedWString& aOriginal) { fmt::wmemory_buffer buffer; if (m_hasScriptsBlob) @@ -90,10 +90,13 @@ std::wstring ScriptCompilationSystem::GetCompilationArgs(const FixedWString& aOr for (const auto& [plugin, path] : m_scriptPaths) { spdlog::info(L"{}: '{}'", plugin->GetName(), path); - pathsFile << path << std::endl; + pathsFile << path.wstring() << std::endl; } spdlog::info(L"Paths written to: '{}'", pathsFilePath); - format_to(std::back_inserter(buffer), LR"( -compilePathsFile "{}"\0)", pathsFilePath); - spdlog::info(L"Final redscript compilation arg string: '{}'", buffer.data()); + format_to(std::back_inserter(buffer), LR"( -compilePathsFile "{}"{})", pathsFilePath, '\0'); return buffer.data(); } + +bool ScriptCompilationSystem::HasScripts() const { + return !m_scriptPaths.empty(); +} diff --git a/src/dll/Systems/ScriptCompilationSystem.hpp b/src/dll/Systems/ScriptCompilationSystem.hpp index 085610c5..91f0d1c5 100644 --- a/src/dll/Systems/ScriptCompilationSystem.hpp +++ b/src/dll/Systems/ScriptCompilationSystem.hpp @@ -4,13 +4,7 @@ #include "ISystem.hpp" #include "Paths.hpp" #include "PluginBase.hpp" - -struct FixedWString -{ - uint32_t length; - uint32_t maxLength; - const wchar_t* str; -}; +#include class ScriptCompilationSystem : public ISystem { @@ -27,7 +21,9 @@ class ScriptCompilationSystem : public ISystem void SetScriptsBlob(const std::filesystem::path& aPath); const std::filesystem::path& GetScriptsBlob() const; - std::wstring GetCompilationArgs(const FixedWString& aOriginal); + std::wstring GetCompilationArgs(const RED4ext::Process::FixedWString& aOriginal); + + bool HasScripts() const; private: using Map_t = std::unordered_multimap, std::filesystem::path>;