aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-07-21 16:40:01 +0100
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-07-21 16:40:01 +0100
commit8564c36b49f5f0451be5036371e421a44425b02e (patch)
treefcd1fbe100e7c8fb9ba7eee8e5923abd5ad0ba27
parent8650a7520baec35765bc837d9313325e0c7631d3 (diff)
downloadNorthstarLauncher-8564c36b49f5f0451be5036371e421a44425b02e.tar.gz
NorthstarLauncher-8564c36b49f5f0451be5036371e421a44425b02e.zip
add some basic filesystem stuff and client/ui script callbacks
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj2
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters6
-rw-r--r--NorthstarDedicatedTest/dedicated.cpp9
-rw-r--r--NorthstarDedicatedTest/dllmain.cpp2
-rw-r--r--NorthstarDedicatedTest/filesystem.cpp53
-rw-r--r--NorthstarDedicatedTest/filesystem.h70
-rw-r--r--NorthstarDedicatedTest/logging.cpp4
-rw-r--r--NorthstarDedicatedTest/modmanager.cpp5
-rw-r--r--NorthstarDedicatedTest/squirrel.cpp92
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(&currentTime, "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)