mirror of
https://github.com/R2Northstar/NorthstarLauncher
synced 2026-08-23 20:26:04 -04:00
add some basic filesystem stuff and client/ui script callbacks
This commit is contained in:
parent
8650a7520b
commit
8564c36b49
9 changed files with 234 additions and 9 deletions
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
53
NorthstarDedicatedTest/filesystem.cpp
Normal file
53
NorthstarDedicatedTest/filesystem.cpp
Normal file
|
|
@ -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);
|
||||
}
|
||||
70
NorthstarDedicatedTest/filesystem.h
Normal file
70
NorthstarDedicatedTest/filesystem.h
Normal file
|
|
@ -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;
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -220,6 +220,11 @@ void ModManager::LoadMods()
|
|||
|
||||
}
|
||||
|
||||
std::vector<Mod*> ModManager::GetMods()
|
||||
{
|
||||
return loadedMods;
|
||||
}
|
||||
|
||||
void InitialiseModManager(HMODULE baseAddress)
|
||||
{
|
||||
g_ModManager = new ModManager();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue