diff options
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters | 6 | ||||
-rw-r--r-- | NorthstarDedicatedTest/dedicated.cpp | 9 | ||||
-rw-r--r-- | NorthstarDedicatedTest/dllmain.cpp | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/filesystem.cpp | 53 | ||||
-rw-r--r-- | NorthstarDedicatedTest/filesystem.h | 70 | ||||
-rw-r--r-- | NorthstarDedicatedTest/logging.cpp | 4 | ||||
-rw-r--r-- | NorthstarDedicatedTest/modmanager.cpp | 5 | ||||
-rw-r--r-- | NorthstarDedicatedTest/squirrel.cpp | 92 |
9 files changed, 234 insertions, 9 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index af4f5663..a565acab 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -174,6 +174,7 @@ <ClInclude Include="context.h" /> <ClInclude Include="convar.h" /> <ClInclude Include="dedicated.h" /> + <ClInclude Include="filesystem.h" /> <ClInclude Include="hooks.h" /> <ClInclude Include="hookutils.h" /> <ClInclude Include="include\MinHook.h" /> @@ -318,6 +319,7 @@ <ClCompile Include="convar.cpp" /> <ClCompile Include="dedicated.cpp" /> <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="filesystem.cpp" /> <ClCompile Include="hooks.cpp" /> <ClCompile Include="hookutils.cpp" /> <ClCompile Include="logging.cpp" /> diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 4f4356f5..74491c39 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -507,6 +507,9 @@ <ClInclude Include="include\rapidjson\msinttypes\stdint.h"> <Filter>Header Files\include\rapidjson\msinttypes</Filter> </ClInclude> + <ClInclude Include="filesystem.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp"> @@ -554,6 +557,9 @@ <ClCompile Include="modmanager.cpp"> <Filter>Source Files\Shared\Mods</Filter> </ClCompile> + <ClCompile Include="filesystem.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="include\spdlog\fmt\bundled\LICENSE.rst"> diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index b3f66d59..d526fb1b 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -11,6 +11,15 @@ bool IsDedicated() return false; } +enum EngineState_t +{ + DLL_INACTIVE = 0, // no dll + DLL_ACTIVE, // engine is focused + DLL_CLOSE, // closing down dll + DLL_RESTART, // engine is shutting down but will restart right away + DLL_PAUSED, // engine is paused, can become active from this state +}; + void InitialiseDedicated(HMODULE engineAddress) { std::cout << "InitialiseDedicated()" << std::endl; diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 4e4978c9..70462e34 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -7,6 +7,7 @@ #include "logging.h" #include "concommand.h" #include "modmanager.h" +#include "filesystem.h" #include <iostream> bool initialised = false; @@ -55,6 +56,7 @@ void InitialiseNorthstar() AddDllLoadCallback("server.dll", InitialiseServerSquirrel); + AddDllLoadCallback("filesystem_stdio.dll", InitialiseFilesystem); // do this after all the other callbacks AddDllLoadCallback("engine.dll", InitialiseModManager); diff --git a/NorthstarDedicatedTest/filesystem.cpp b/NorthstarDedicatedTest/filesystem.cpp new file mode 100644 index 00000000..135201b6 --- /dev/null +++ b/NorthstarDedicatedTest/filesystem.cpp @@ -0,0 +1,53 @@ +#include "pch.h" +#include "filesystem.h" +#include "hooks.h" +#include "hookutils.h" +#include "sourceinterface.h" + +// hook forward declares +typedef FileHandle_t(*ReadFileFromVPKType)(VPKData* vpkInfo, __int64* b, const char* filename); +ReadFileFromVPKType readFileFromVPK; +FileHandle_t ReadFileFromVPKHook(VPKData* vpkInfo, __int64* b, const char* filename); + +typedef bool(*ReadFromCacheType)(IFileSystem* filesystem, const char* path, void* result); +ReadFromCacheType readFromCache; +bool ReadFromCacheHook(IFileSystem* filesystem, const char* path, void* result); + +SourceInterface<IFileSystem>* g_Filesystem; + +void InitialiseFilesystem(HMODULE baseAddress) +{ + g_Filesystem = new SourceInterface<IFileSystem>("filesystem_stdio.dll", "VFileSystem017"); + + // create hooks + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x5CBA0, &ReadFileFromVPKHook, reinterpret_cast<LPVOID*>(&readFileFromVPK)); + ENABLER_CREATEHOOK(hook, (*g_Filesystem)->m_vtable->ReadFromCache, &ReadFromCacheHook, reinterpret_cast<LPVOID*>(&readFromCache)); +} + +bool ShouldReplaceFile(const char* path) +{ + return false; +} + +FileHandle_t ReadFileFromVPKHook(VPKData* vpkInfo, __int64* b, const char* filename) +{ + // move this to a convar at some point when we can read them in native + //spdlog::info("ReadFileFromVPKHook {} {}", filename, vpkInfo->path); + if (ShouldReplaceFile(filename)) + { + *b = -1; + return b; + } + + return readFileFromVPK(vpkInfo, b, filename); +} + +bool ReadFromCacheHook(IFileSystem* filesystem, const char* path, void* result) +{ + // move this to a convar at some point when we can read them in native + //spdlog::info("ReadFromCacheHook {}", path); + + + return readFromCache(filesystem, path, result); +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/filesystem.h b/NorthstarDedicatedTest/filesystem.h new file mode 100644 index 00000000..597a03ff --- /dev/null +++ b/NorthstarDedicatedTest/filesystem.h @@ -0,0 +1,70 @@ +#pragma once +#include "sourceinterface.h" + +// taken from ttf2sdk +typedef void* FileHandle_t; + +#pragma pack(push,1) +struct VPKFileEntry +{ + char* directory; + char* filename; + char* extension; + unsigned char unknown[0x38]; +}; +#pragma pack(pop) + +#pragma pack(push,1) +struct VPKData +{ + unsigned char unknown[5]; + char path[255]; + unsigned char unknown2[0x134]; + int32_t numEntries; + unsigned char unknown3[12]; + VPKFileEntry* entries; +}; +#pragma pack(pop) + +enum SearchPathAdd_t +{ + PATH_ADD_TO_HEAD, // First path searched + PATH_ADD_TO_TAIL, // Last path searched +}; + +class CSearchPath +{ +public: + unsigned char unknown[0x18]; + const char* debugPath; +}; + +class IFileSystem +{ +public: + struct VTable + { + void* unknown[10]; + void(*AddSearchPath) (IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType); + void* unknown2[84]; + bool(*ReadFromCache) (IFileSystem* fileSystem, const char* path, void* result); + void* unknown3[15]; + VPKData* (*MountVPK) (IFileSystem* fileSystem, const char* vpkPath); + }; + + struct VTable2 + { + int(*Read) (IFileSystem::VTable2** fileSystem, void* pOutput, int size, FileHandle_t file); + void* unknown[1]; + FileHandle_t(*Open) (IFileSystem::VTable2** fileSystem, const char* pFileName, const char* pOptions, const char* pathID, int64_t unknown); + void(*Close) (IFileSystem* fileSystem, FileHandle_t file); + void* unknown2[6]; + bool(*FileExists)(IFileSystem::VTable2** fileSystem, const char* pFileName, const char* pPathID); + }; + + VTable* m_vtable; + VTable2* m_vtable2; +}; + +void InitialiseFilesystem(HMODULE baseAddress); +extern SourceInterface<IFileSystem>* g_Filesystem;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index 66f2de4c..721c00f5 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -1,6 +1,5 @@ #include "pch.h" #include "logging.h" -#include "context.h" #include "sourceconsole.h" #include "spdlog/sinks/basic_file_sink.h" #include <iomanip> @@ -14,11 +13,14 @@ void InitialiseLogging() spdlog::default_logger()->set_pattern("[%H:%M:%S] [%l] %v"); spdlog::flush_on(spdlog::level::info); + // log file stuff // generate log file, format should be nslog%d-%m-%Y %H-%M-%S.txt in gamedir/R2Northstar/logs + // todo: might be good to delete logs that are too old time_t time = std::time(nullptr); tm currentTime = *std::localtime(&time); std::stringstream stream; stream << std::put_time(¤tTime, "R2Northstar/logs/nslog%d-%m-%Y %H-%M-%S.txt"); + // create logger spdlog::default_logger()->sinks().push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(stream.str(), false)); }
\ No newline at end of file diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index a45d2b2a..c85c17c8 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -220,6 +220,11 @@ void ModManager::LoadMods() } +std::vector<Mod*> ModManager::GetMods() +{ + return loadedMods; +} + void InitialiseModManager(HMODULE baseAddress) { g_ModManager = new ModManager(); diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index 27b997ab..43a45779 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -4,6 +4,7 @@ #include "hookutils.h" #include "sigscanning.h" #include "concommand.h" +#include "modmanager.h" #include <iostream> // hook forward declarations @@ -23,10 +24,15 @@ DestroyVMType ClientDestroyVM; // only need a client one since ui doesn't have i DestroyVMType ServerDestroyVM; template<Context context> void DestroyVMHook(void* a1, void* sqvm); -typedef void (*SQCompileErrorType)(void* sqvm, const char* error, const char* file, int line, int column); -SQCompileErrorType ClientSQCompileError; // only need a client one since ui doesn't have its own func for this -SQCompileErrorType ServerSQCompileError; -template<Context context> void SQCompileErrorHook(void* sqvm, const char* error, const char* file, int line, int column); +typedef void(*ScriptCompileError)(void* sqvm, const char* error, const char* file, int line, int column); +ScriptCompileError ClientSQCompileError; // only need a client one since ui doesn't have its own func for this +ScriptCompileError ServerSQCompileError; +template<Context context> void ScriptCompileErrorHook(void* sqvm, const char* error, const char* file, int line, int column); + +typedef char(*CallScriptInitCallbackType)(void* sqvm, const char* callback); +CallScriptInitCallbackType ClientCallScriptInitCallback; +CallScriptInitCallbackType ServerCallScriptInitCallback; +template<Context context> char CallScriptInitCallbackHook(void* sqvm, const char* callback); sq_compilebufferType ClientSq_compilebuffer; sq_compilebufferType ServerSq_compilebuffer; @@ -65,7 +71,8 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26130, &CreateNewVMHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientCreateNewVM)); // client createnewvm function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E70, &DestroyVMHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientDestroyVM)); // client destroyvm function - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x79A50, &SQCompileErrorHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientSQCompileError)); // client compileerror function + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x79A50, &ScriptCompileErrorHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientSQCompileError)); // client compileerror function + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x10190, &CallScriptInitCallbackHook<CLIENT>, reinterpret_cast<LPVOID*>(&ClientCallScriptInitCallback)); // client callscriptinitcallback function } void InitialiseServerSquirrel(HMODULE baseAddress) @@ -81,7 +88,7 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQPrint)); // server print function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x260E0, &CreateNewVMHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerCreateNewVM)); // server createnewvm function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E20, &DestroyVMHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerDestroyVM)); // server destroyvm function - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x799E0, &SQCompileErrorHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQCompileError)); // server compileerror function + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x799E0, &ScriptCompileErrorHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQCompileError)); // server compileerror function RegisterConCommand("script", ExecuteCodeCommand<SERVER>, "Executes script code in the server vm", FCVAR_GAMEDLL); } @@ -155,12 +162,12 @@ template<Context context> void DestroyVMHook(void* a1, void* sqvm) spdlog::info("DestroyVM {} {}", GetContextName(realContext), sqvm); } -template<Context context> void SQCompileErrorHook(void* sqvm, const char* error, const char* file, int line, int column) +template<Context context> void ScriptCompileErrorHook(void* sqvm, const char* error, const char* file, int line, int column) { // note: i think vanilla might actually show the script line that errored, might be nice to implement that if it's a thing // look into client.dll+79540 for way better errors too - Context realContext = context; + Context realContext = context; // ui and client use the same function so we use this for prints if (context == CLIENT && sqvm == g_UISquirrelManager->sqvm) realContext = UI; @@ -173,6 +180,75 @@ template<Context context> void SQCompileErrorHook(void* sqvm, const char* error, // though, that also has potential to be REALLY bad if we're compiling ui scripts lol } +template<Context context> char CallScriptInitCallbackHook(void* sqvm, const char* callback) +{ + char ret; + + if (context == CLIENT) + { + Context realContext = context; // ui and client use the same function so we use this for prints + bool shouldCallCustomCallbacks = false; + + // since we don't hook arbitrary callbacks yet, make sure we're only doing callbacks on inits + if (!strcmp(callback, "UICodeCallback_UIInit")) + { + realContext = UI; + shouldCallCustomCallbacks = true; + } + else if (!strcmp(callback, "ClientCodeCallback_MapSpawn")) + shouldCallCustomCallbacks = true; + + // run before callbacks + if (shouldCallCustomCallbacks) + { + for (Mod* mod : g_ModManager->GetMods()) + { + for (ModScript* script : mod->Scripts) + { + for (ModScriptCallback* modCallback : script->Callbacks) + { + if (modCallback->Context == realContext && modCallback->BeforeCallback.length()) + { + spdlog::info("Running custom {} script callback \"{}\"", GetContextName(realContext), modCallback->BeforeCallback); + ClientCallScriptInitCallback(sqvm, modCallback->BeforeCallback.c_str()); + } + } + } + } + } + + spdlog::info("{} CodeCallback {} called", GetContextName(realContext), callback); + if (!shouldCallCustomCallbacks) + spdlog::info("Not executing custom callbacks for CodeCallback {}", callback); + ret = ClientCallScriptInitCallback(sqvm, callback); + + // run after callbacks + if (shouldCallCustomCallbacks) + { + for (Mod* mod : g_ModManager->GetMods()) + { + for (ModScript* script : mod->Scripts) + { + for (ModScriptCallback* modCallback : script->Callbacks) + { + if (modCallback->Context == realContext && modCallback->AfterCallback.length()) + { + spdlog::info("Running custom {} script callback \"{}\"", GetContextName(realContext), modCallback->AfterCallback); + ClientCallScriptInitCallback(sqvm, modCallback->AfterCallback.c_str()); + } + } + } + } + } + } + else if (context == SERVER) + { + // todo lol + } + + return ret; +} + template<Context context> void ExecuteCodeCommand(const CCommand& args) { if (context == CLIENT) |