From 22a1ce87fa1205aa15eff81d78dc7c0e87c251c9 Mon Sep 17 00:00:00 2001 From: Maya Date: Tue, 5 Jul 2022 01:39:59 +0200 Subject: Move #include top of file in ExploitFixes (#218) * Move Include in ExploitFixes * Formatting --- NorthstarDedicatedTest/ExploitFixes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/ExploitFixes.cpp b/NorthstarDedicatedTest/ExploitFixes.cpp index 44b62d55..0f8569b5 100644 --- a/NorthstarDedicatedTest/ExploitFixes.cpp +++ b/NorthstarDedicatedTest/ExploitFixes.cpp @@ -4,6 +4,7 @@ #include "ExploitFixes_UTF8Parser.h" #include "NSMem.h" #include "cvar.h" +#include "gameutils.h" ConVar* ns_exploitfixes_log; #define SHOULD_LOG (ns_exploitfixes_log->m_Value.m_nValue > 0) @@ -271,7 +272,6 @@ INVALID_CMD: // basically: by default r2 isn't set as a valve mod, meaning that m_bRestrictServerCommands is false // this is HORRIBLE for security, because it means servers can run arbitrary concommands on clients // especially since we have script commands this could theoretically be awful -#include "gameutils.h" typedef void (*IsValveModType)(); IsValveModType IsValveMod; -- cgit v1.2.3 From 5995a7462da970ee2102a0dd0047ebbcef519dd0 Mon Sep 17 00:00:00 2001 From: KittenPopo Date: Mon, 4 Jul 2022 17:19:57 -0700 Subject: Fix KHook hooking order to prevent missed hooks (#213) --- NorthstarDedicatedTest/ExploitFixes.cpp | 68 ++++++++++++++++++++++----------- NorthstarDedicatedTest/ExploitFixes.h | 8 ++-- NorthstarDedicatedTest/NSMem.h | 20 +--------- NorthstarDedicatedTest/dllmain.cpp | 12 ++++-- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/NorthstarDedicatedTest/ExploitFixes.cpp b/NorthstarDedicatedTest/ExploitFixes.cpp index 0f8569b5..2f4e2b5c 100644 --- a/NorthstarDedicatedTest/ExploitFixes.cpp +++ b/NorthstarDedicatedTest/ExploitFixes.cpp @@ -272,13 +272,11 @@ INVALID_CMD: // basically: by default r2 isn't set as a valve mod, meaning that m_bRestrictServerCommands is false // this is HORRIBLE for security, because it means servers can run arbitrary concommands on clients // especially since we have script commands this could theoretically be awful - -typedef void (*IsValveModType)(); -IsValveModType IsValveMod; - -bool IsValveModHook() +KHOOK(IsValveMod, ("engine.dll", "48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 85 C0 74 63"), bool, __fastcall, ()) { - return !CommandLine()->CheckParm("-norestrictservercommands"); + bool result = !CommandLine()->CheckParm("-norestrictservercommands"); + spdlog::info("ExploitFixes: Overriding IsValveMod to {}...", result); + return result; } // Fix respawn's crappy UTF8 parser so it doesn't crash -_- @@ -490,36 +488,62 @@ KHOOK( return oSpecialClientCommand(player, command); } -void ExploitFixes::LoadCallback(HMODULE baseAddress) +void SetupKHook(KHook* hook) { - spdlog::info("ExploitFixes::LoadCallback ..."); - - spdlog::info("\tByte patching..."); - DoBytePatches(); - - if (KHook::InitAllHooks()) + if (hook->Setup()) { - spdlog::info("\tInitialized " + std::to_string(KHook::_allHooks.size()) + " exploit-patch hooks."); + spdlog::debug("KHook::Setup(): Hooked at {}", hook->targetFuncAddr); } else { spdlog::critical("\tFAILED to initialize all exploit patches."); - // Force exit? + // Force exit MessageBoxA(0, "FAILED to initialize all exploit patches.", "Northstar", MB_ICONERROR); exit(0); } +} - ns_exploitfixes_log = - new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something"); +void ExploitFixes::LoadCallback_MultiModule(HMODULE baseAddress) +{ - HookEnabler hook; - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x2a8a50, &GetEntByIndexHook, reinterpret_cast(&GetEntByIndex)); + spdlog::info("ExploitFixes::LoadCallback_MultiModule({}) ...", (void*)baseAddress); + + int hooksEnabled = 0; + for (auto itr = KHook::_allHooks.begin(); itr != KHook::_allHooks.end(); itr++) + { + auto curHook = *itr; + if (GetModuleHandleA(curHook->targetFunc.moduleName) == baseAddress) + { + SetupKHook(curHook); + itr = KHook::_allHooks.erase(itr); // Prevent repeated initialization + + hooksEnabled++; + + if (itr == KHook::_allHooks.end()) + break; + } + } + + spdlog::info("\tEnabled {} hooks.", hooksEnabled); } -void ExploitFixes::LoadCallbackEngine(HMODULE baseAddress) +void ExploitFixes::LoadCallback_Full(HMODULE baseAddress) { - spdlog::info("ExploitFixes::LoadCallbackEngine ..."); + spdlog::info("ExploitFixes::LoadCallback_Full ..."); + + spdlog::info("\tByte patching..."); + DoBytePatches(); + + for (KHook* hook : KHook::_allHooks) + SetupKHook(hook); + + spdlog::info("\tInitialized " + std::to_string(KHook::_allHooks.size()) + " late exploit-patch hooks."); + KHook::_allHooks.clear(); + + ns_exploitfixes_log = + new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something"); + HookEnabler hook; - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1C6360, &IsValveModHook, reinterpret_cast(&IsValveMod)); + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x2a8a50, &GetEntByIndexHook, reinterpret_cast(&GetEntByIndex)); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/ExploitFixes.h b/NorthstarDedicatedTest/ExploitFixes.h index 1cafe758..d0754d72 100644 --- a/NorthstarDedicatedTest/ExploitFixes.h +++ b/NorthstarDedicatedTest/ExploitFixes.h @@ -5,6 +5,8 @@ namespace ExploitFixes { - void LoadCallback(HMODULE unused); - void LoadCallbackEngine(HMODULE baseAddress); -} // namespace ExploitFixes \ No newline at end of file + // This callback will be ran muliple times on multiple module loads + void LoadCallback_MultiModule(HMODULE baseAddress); + + void LoadCallback_Full(HMODULE unused); +} // namespace ExploitFixes diff --git a/NorthstarDedicatedTest/NSMem.h b/NorthstarDedicatedTest/NSMem.h index 74df3a84..84bb93db 100644 --- a/NorthstarDedicatedTest/NSMem.h +++ b/NorthstarDedicatedTest/NSMem.h @@ -182,25 +182,7 @@ struct KHook if (!targetFuncAddr) return false; - return MH_CreateHook(targetFuncAddr, hookFunc, original) == MH_OK; - } - - // Returns true if succeeded - static bool InitAllHooks() - { - for (KHook* hook : _allHooks) - { - if (hook->Setup()) - { - spdlog::info("KHook hooked at {}", hook->targetFuncAddr); - } - else - { - return false; - } - } - - return MH_EnableHook(MH_ALL_HOOKS) == MH_OK; + return (MH_CreateHook(targetFuncAddr, hookFunc, original) == MH_OK) && (MH_EnableHook(targetFuncAddr) == MH_OK); } }; #define KHOOK(name, funcPatternInfo, returnType, convention, args) \ diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 08081d78..04cb883b 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -285,9 +285,15 @@ bool InitialiseNorthstar() // mod manager after everything else AddDllLoadCallback("engine.dll", InitialiseModManager); - // activate exploit fixes - AddDllLoadCallback("server.dll", ExploitFixes::LoadCallback); - AddDllLoadCallback("engine.dll", ExploitFixes::LoadCallbackEngine); + { + // activate multi-module exploitfixes callbacks + constexpr const char* EXPLOITFIXES_MULTICALLBACK_MODS[] = {"client.dll", "engine.dll", "server.dll"}; + for (const char* mod : EXPLOITFIXES_MULTICALLBACK_MODS) + AddDllLoadCallback(mod, ExploitFixes::LoadCallback_MultiModule); + + // activate exploit fixes later + AddDllLoadCallback("server.dll", ExploitFixes::LoadCallback_Full); + } // run callbacks for any libraries that are already loaded by now CallAllPendingDLLLoadCallbacks(); -- cgit v1.2.3 From 9f8190486e04c66483dc8cd0ca9fd92fc732789a Mon Sep 17 00:00:00 2001 From: Maya Date: Sat, 9 Jul 2022 00:17:05 +0200 Subject: Add StringToAsset function to squirrel (#216) * Add StringToAsset function to squirrel also added better values for return type enum because otherwise asset can't be returned without casting * Formatting * Switched to a template for the stringToAsset function also renamed files but have to do it in 2 commits because git ignores file case * Rename step 2 * change to lowercase in include * changed to lowercase in include inside dllmain --- .../NorthstarDedicatedTest.vcxproj | 2 ++ .../NorthstarDedicatedTest.vcxproj.filters | 6 +++++ NorthstarDedicatedTest/dllmain.cpp | 3 +++ NorthstarDedicatedTest/scriptutility.cpp | 29 ++++++++++++++++++++++ NorthstarDedicatedTest/scriptutility.h | 4 +++ NorthstarDedicatedTest/squirrel.cpp | 29 ++++++++++++++++++++++ NorthstarDedicatedTest/squirrel.h | 25 +++++++++++++++++-- 7 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 NorthstarDedicatedTest/scriptutility.cpp create mode 100644 NorthstarDedicatedTest/scriptutility.h diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index ea9ccbb3..ff6ca2ea 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -121,6 +121,7 @@ + @@ -616,6 +617,7 @@ + diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 576b9004..0e48f4a0 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1515,6 +1515,9 @@ Header Files\Shared\ExploitFixes + + Header Files\Shared + @@ -1682,6 +1685,9 @@ Source Files\Client + + Source Files\Shared + diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 04cb883b..d64cc34f 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -45,6 +45,7 @@ #include #include "version.h" #include "pch.h" +#include "scriptutility.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" @@ -255,6 +256,7 @@ bool InitialiseNorthstar() AddDllLoadCallbackForClient("client.dll", InitialiseClientVideoOverrides); AddDllLoadCallbackForClient("engine.dll", InitialiseEngineClientRUIHooks); AddDllLoadCallbackForClient("engine.dll", InitialiseDebugOverlay); + AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrelUtilityFunctions); // audio hooks AddDllLoadCallbackForClient("client.dll", InitialiseMilesAudioHooks); } @@ -267,6 +269,7 @@ bool InitialiseNorthstar() AddDllLoadCallback("server.dll", InitialiseMiscServerScriptCommand); AddDllLoadCallback("server.dll", InitialiseMiscServerFixes); AddDllLoadCallback("server.dll", InitialiseBuildAINFileHooks); + AddDllLoadCallback("server.dll", InitialiseServerSquirrelUtilityFunctions); AddDllLoadCallback("engine.dll", InitialisePlaylistHooks); diff --git a/NorthstarDedicatedTest/scriptutility.cpp b/NorthstarDedicatedTest/scriptutility.cpp new file mode 100644 index 00000000..98c6f3a3 --- /dev/null +++ b/NorthstarDedicatedTest/scriptutility.cpp @@ -0,0 +1,29 @@ +#include "pch.h" +#include "scriptutility.h" +#include "squirrel.h" + +template SQRESULT SQ_StringToAsset(void* sqvm) +{ + if (context == ScriptContext::SERVER) + { + const char* asset = ServerSq_getstring(sqvm, 1); + ServerSq_pushAsset(sqvm, asset, -1); + } + else + { + const char* asset = ClientSq_getstring(sqvm, 1); + ClientSq_pushAsset(sqvm, asset, -1); + } + return SQRESULT_NOTNULL; +} + +void InitialiseClientSquirrelUtilityFunctions(HMODULE baseAddress) +{ + g_ClientSquirrelManager->AddFuncRegistration("asset", "StringToAsset", "string assetName", "", SQ_StringToAsset); + g_UISquirrelManager->AddFuncRegistration("asset", "StringToAsset", "string assetName", "", SQ_StringToAsset); +} + +void InitialiseServerSquirrelUtilityFunctions(HMODULE baseAddress) +{ + g_ServerSquirrelManager->AddFuncRegistration("asset", "StringToAsset", "string assetName", "", SQ_StringToAsset); +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/scriptutility.h b/NorthstarDedicatedTest/scriptutility.h new file mode 100644 index 00000000..2b58ebfb --- /dev/null +++ b/NorthstarDedicatedTest/scriptutility.h @@ -0,0 +1,4 @@ +#pragma once + +void InitialiseClientSquirrelUtilityFunctions(HMODULE baseAddress); +void InitialiseServerSquirrelUtilityFunctions(HMODULE baseAddress); \ No newline at end of file diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index b1c5b4a8..d0d54a3a 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -72,6 +72,9 @@ sq_pushboolType ServerSq_pushbool; sq_pusherrorType ClientSq_pusherror; sq_pusherrorType ServerSq_pusherror; +sq_pushAssetType ClientSq_pushAsset; +sq_pushAssetType ServerSq_pushAsset; + // sq stack get funcs sq_getstringType ClientSq_getstring; sq_getstringType ServerSq_getstring; @@ -136,6 +139,7 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ClientSq_pushfloat = (sq_pushfloatType)((char*)baseAddress + 0x3800); ClientSq_pushbool = (sq_pushboolType)((char*)baseAddress + 0x3710); ClientSq_pusherror = (sq_pusherrorType)((char*)baseAddress + 0x8470); + ClientSq_pushAsset = (sq_pushAssetType)((char*)baseAddress + 0x3560); ClientSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60C0); ClientSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60E0); @@ -190,6 +194,7 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_pushfloat = (sq_pushfloatType)((char*)baseAddress + 0x3800); ServerSq_pushbool = (sq_pushboolType)((char*)baseAddress + 0x3710); ServerSq_pusherror = (sq_pusherrorType)((char*)baseAddress + 0x8440); + ServerSq_pushAsset = (sq_pushAssetType)((char*)baseAddress + 0x3560); ServerSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60A0); ServerSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60C0); @@ -485,4 +490,28 @@ template int64_t RegisterSquirrelFuncHook(void* sqvm, SQ return ServerRegisterSquirrelFunc(sqvm, funcReg, unknown); else return ClientRegisterSquirrelFunc(sqvm, funcReg, unknown); +} + +SQReturnTypeEnum GetReturnTypeEnumFromString(const char* returnTypeString) +{ + + static std::map sqEnumStrMap = { + {"bool", SqReturnBoolean}, + {"float", SqReturnFloat}, + {"vector", SqReturnVector}, + {"int", SqReturnInteger}, + {"entity", SqReturnEntity}, + {"string", SqReturnString}, + {"array", SqReturnArrays}, + {"asset", SqReturnAsset}, + {"table", SqReturnTable}}; + + if (sqEnumStrMap.count(returnTypeString)) + { + return sqEnumStrMap[returnTypeString]; + } + else + { + return SqReturnDefault; // previous default value + } } \ No newline at end of file diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index d6dfcc57..cbdf0c8c 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -18,6 +18,20 @@ const SQRESULT SQRESULT_NOTNULL = 1; typedef SQInteger (*SQFunction)(void* sqvm); +enum SQReturnTypeEnum +{ + SqReturnFloat = 0x1, + SqReturnVector = 0x3, + SqReturnInteger = 0x5, + SqReturnBoolean = 0x6, + SqReturnEntity = 0xD, + SqReturnString = 0x21, + SqReturnDefault = 0x20, + SqReturnArrays = 0x25, + SqReturnAsset = 0x28, + SqReturnTable = 0x26, +}; + struct CompileBufferState { const SQChar* buffer; @@ -43,7 +57,7 @@ struct SQFuncRegistration __int32 devLevel; const char* shortNameMaybe; __int32 unknown2; - __int32 returnTypeEnum; + SQReturnTypeEnum returnTypeEnum; __int32* externalBufferPointer; __int64 externalBufferSize; __int64 unknown3; @@ -53,10 +67,12 @@ struct SQFuncRegistration SQFuncRegistration() { memset(this, 0, sizeof(SQFuncRegistration)); - this->returnTypeEnum = 32; + this->returnTypeEnum = SqReturnDefault; } }; +SQReturnTypeEnum GetReturnTypeEnumFromString(const char* returnTypeString); + // core sqvm funcs typedef SQRESULT (*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, ScriptContext a2); extern sq_compilebufferType ClientSq_compilebuffer; @@ -105,6 +121,10 @@ typedef SQInteger (*sq_pusherrorType)(void* sqvm, const SQChar* error); extern sq_pusherrorType ClientSq_pusherror; extern sq_pusherrorType ServerSq_pusherror; +typedef SQRESULT (*sq_pushAssetType)(void* sqvm, const SQChar* assetName, SQInteger nameLength); +extern sq_pushAssetType ServerSq_pushAsset; +extern sq_pushAssetType ClientSq_pushAsset; + // sq stack get funcs typedef const SQChar* (*sq_getstringType)(void* sqvm, SQInteger stackpos); extern sq_getstringType ClientSq_getstring; @@ -277,6 +297,7 @@ template class SquirrelManager reg->returnTypeString = new char[returnType.size() + 1]; strcpy((char*)reg->returnTypeString, returnType.c_str()); + reg->returnTypeEnum = GetReturnTypeEnumFromString(returnType.c_str()); reg->argTypes = new char[argTypes.size() + 1]; strcpy((char*)reg->argTypes, argTypes.c_str()); -- cgit v1.2.3 From 151d678453f3e321fcccf2512e6e2f53436f1469 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 8 Jul 2022 23:21:13 +0100 Subject: Add Postload support for rpaks (#217) * fixed custom rpaks being loaded more than once * formatting * better things, although LoadPakSyncHook is annoying * formatting * removing unnecessary comments and stuff (whoops) * Moving to use PakLoadManager * formatting * postload things * formatting * trailing space smh --- NorthstarDedicatedTest/modmanager.cpp | 7 +++++++ NorthstarDedicatedTest/modmanager.h | 1 + NorthstarDedicatedTest/rpakfilesystem.cpp | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 50c7b371..9de1c7b1 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -383,6 +383,13 @@ void ModManager::LoadMods() modPak.m_bAutoLoad = !bUseRpakJson || (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() && dRpakJson["Preload"].HasMember(pakName) && dRpakJson["Preload"][pakName].IsTrue()); + // postload things + if (!bUseRpakJson || + (dRpakJson.HasMember("Postload") && dRpakJson["Postload"].IsObject() && dRpakJson["Postload"].HasMember(pakName))) + { + modPak.m_sLoadAfterPak = dRpakJson["Postload"][pakName].GetString(); + } + modPak.m_sPakName = pakName; // not using atm because we need to resolve path to rpak diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 798c2306..00c0384a 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -57,6 +57,7 @@ struct ModRpakEntry public: bool m_bAutoLoad; std::string m_sPakName; + std::string m_sLoadAfterPak; }; class Mod diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp index b3105996..1a4736a9 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.cpp +++ b/NorthstarDedicatedTest/rpakfilesystem.cpp @@ -108,6 +108,23 @@ void LoadPreloadPaks() } } +void LoadPostloadPaks(char** map) +{ + // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks + for (Mod& mod : g_ModManager->m_loadedMods) + { + if (!mod.Enabled) + continue; + + // need to get a relative path of mod to mod folder + fs::path modPakPath("./" / mod.ModDirectory / "paks"); + + for (ModRpakEntry& pak : mod.Rpaks) + if (pak.m_sLoadAfterPak == *map) + g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), false); + } +} + void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName) { // whether the vanilla game has this rpak @@ -212,6 +229,8 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba // add the hash to the map g_PakLoadManager->AddLoadedPak(ret, hash); + LoadPostloadPaks(&path); + if (bNeedToFreePakName) delete[] path; -- cgit v1.2.3 From 85635ad99dbdfa909341e4138f6fdb0c9bf73bf1 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Sun, 10 Jul 2022 18:22:59 +0300 Subject: Add dependency constants (#156) * Fix duplicate script in scripts.rson when 2 mods add a custom script with the same path Allow mods to force a VPK to load through vpk.json * Remove unnecessary print * Fix match predicate using the value instead of the name * - Add a dependency constant system for use in compile flags - Remove the duplicate script engine error fix - Add ClientSq_defconst & ServerSq_defconst * Format fix * - Fix access violation - Separate dependency constants into mod and add checks for conflicts * - Remove unnecessary comment * Remove VPK loading for now and allow 2 mods to use the same constant if the mod names match * Fix bugs * fix mistake * fix keyvalues not working with modded files * simplify code * Fix formatting * Remove keyvalues fix --- NorthstarDedicatedTest/modmanager.cpp | 34 ++++++++++++++++++++++++++++++++++ NorthstarDedicatedTest/modmanager.h | 6 ++++++ NorthstarDedicatedTest/squirrel.cpp | 7 +++++++ NorthstarDedicatedTest/squirrel.h | 21 +++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 9de1c7b1..de45bd23 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -186,6 +186,26 @@ Mod::Mod(fs::path modDir, char* jsonBuf) } } + if (modJson.HasMember("Dependencies") && modJson["Dependencies"].IsObject()) + { + for (auto v = modJson["Dependencies"].MemberBegin(); v != modJson["Dependencies"].MemberEnd(); v++) + { + if (!v->name.IsString() || !v->value.IsString()) + continue; + + spdlog::info("Constant {} defined by {} for mod {}", v->name.GetString(), Name, v->value.GetString()); + if (DependencyConstants.find(v->name.GetString()) != DependencyConstants.end() && + v->value.GetString() != DependencyConstants[v->name.GetString()]) + { + spdlog::error("A dependency constant with the same name already exists for another mod. Change the constant name."); + return; + } + + if (DependencyConstants.find(v->name.GetString()) == DependencyConstants.end()) + DependencyConstants.emplace(v->name.GetString(), v->value.GetString()); + } + } + wasReadSuccessfully = true; } @@ -212,6 +232,8 @@ void ModManager::LoadMods() fs::remove_all(GetCompiledAssetsPath()); fs::create_directories(GetModFolderPath()); + DependencyConstants.clear(); + // read enabled mods cfg std::ifstream enabledModsStream(GetNorthstarPrefix() + "/enabledmods.json"); std::stringstream enabledModsStringStream; @@ -253,6 +275,18 @@ void ModManager::LoadMods() Mod mod(modDir, (char*)jsonStringStream.str().c_str()); + for (auto& pair : mod.DependencyConstants) + { + if (DependencyConstants.find(pair.first) != DependencyConstants.end() && DependencyConstants[pair.first] != pair.second) + { + spdlog::error("Constant {} in mod {} already exists in another mod.", pair.first, mod.Name); + mod.wasReadSuccessfully = false; + break; + } + if (DependencyConstants.find(pair.first) == DependencyConstants.end()) + DependencyConstants.emplace(pair); + } + if (m_hasEnabledModsCfg && m_enabledModsCfg.HasMember(mod.Name.c_str())) mod.Enabled = m_enabledModsCfg[mod.Name.c_str()].IsTrue(); else diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 00c0384a..d605eec2 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -100,6 +100,9 @@ class Mod std::vector Rpaks; std::unordered_map RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite + // iterated over to create squirrel VM constants depending if a mod exists or not. + // this only exists because we cannot access g_ModManager whilst mods are being loaded for the first time for some reason. + std::unordered_map DependencyConstants; // other stuff @@ -130,6 +133,9 @@ class ModManager public: std::vector m_loadedMods; std::unordered_map m_modFiles; + // iterated over to create squirrel VM constants depending if a mod exists or not. + // here because constants are global anyways. + std::unordered_map DependencyConstants; public: ModManager(); diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index d0d54a3a..a0680d9a 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -72,6 +72,9 @@ sq_pushboolType ServerSq_pushbool; sq_pusherrorType ClientSq_pusherror; sq_pusherrorType ServerSq_pusherror; +sq_defconst ClientSq_defconst; +sq_defconst ServerSq_defconst; + sq_pushAssetType ClientSq_pushAsset; sq_pushAssetType ServerSq_pushAsset; @@ -148,6 +151,8 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ClientSq_sq_get = (sq_getType)((char*)baseAddress + 0x7C30); + ClientSq_defconst = (sq_defconst)((char*)baseAddress + 0x12120); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x26130, @@ -203,6 +208,8 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_sq_get = (sq_getType)((char*)baseAddress + 0x7C00); + ServerSq_defconst = (sq_defconst)((char*)baseAddress + 0x1F550); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x1FE90, diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index cbdf0c8c..0e49c7f8 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -1,3 +1,4 @@ +#include <../modmanager.h> #pragma once void InitialiseClientSquirrel(HMODULE baseAddress); @@ -121,6 +122,10 @@ typedef SQInteger (*sq_pusherrorType)(void* sqvm, const SQChar* error); extern sq_pusherrorType ClientSq_pusherror; extern sq_pusherrorType ServerSq_pusherror; +typedef void (*sq_defconst)(void* sqvm, const SQChar* name, int value); +extern sq_defconst ClientSq_defconst; +extern sq_defconst ServerSq_defconst; + typedef SQRESULT (*sq_pushAssetType)(void* sqvm, const SQChar* assetName, SQInteger nameLength); extern sq_pushAssetType ServerSq_pushAsset; extern sq_pushAssetType ClientSq_pushAsset; @@ -172,6 +177,22 @@ template class SquirrelManager else ServerRegisterSquirrelFunc(sqvm, funcReg, 1); } + for (auto& pair : g_ModManager->DependencyConstants) + { + bool wasFound = false; + for (Mod& dependency : g_ModManager->m_loadedMods) + { + if (dependency.Name == pair.second) + { + wasFound = dependency.Enabled; + break; + } + } + if (context == ScriptContext::SERVER) + ServerSq_defconst(sqvm, pair.first.c_str(), wasFound); + else + ClientSq_defconst(sqvm, pair.first.c_str(), wasFound); + } } void VMDestroyed() -- cgit v1.2.3