From 97df63bc21e53556f3cc31112f713d1ae63e691a Mon Sep 17 00:00:00 2001 From: pg9182 <96569817+pg9182@users.noreply.github.com> Date: Fri, 5 May 2023 19:45:04 -0400 Subject: Revert "Plugin system v2 (#343)" This reverts commit 450d0b1ed437cf37b4309af952af8904f3f07768. --- NorthstarDLL/NorthstarDLL.vcxproj | 5 +- NorthstarDLL/NorthstarDLL.vcxproj.filters | 27 +- NorthstarDLL/config/profile.cpp | 3 + NorthstarDLL/core/convar/concommand.cpp | 4 - NorthstarDLL/core/convar/convar.cpp | 7 - NorthstarDLL/core/hooks.cpp | 2 + NorthstarDLL/core/math/color.cpp | 2 - NorthstarDLL/core/math/color.h | 2 - NorthstarDLL/dllmain.cpp | 135 ++++- NorthstarDLL/engine/hoststate.cpp | 4 - NorthstarDLL/logging/logging.cpp | 10 - NorthstarDLL/logging/logging.h | 3 - NorthstarDLL/masterserver/masterserver.cpp | 9 +- NorthstarDLL/masterserver/masterserver.h | 5 +- NorthstarDLL/mods/modmanager.cpp | 5 - NorthstarDLL/mods/modmanager.h | 2 - NorthstarDLL/pch.h | 6 - NorthstarDLL/plugins/plugin_abi.h | 192 ++----- NorthstarDLL/plugins/pluginbackend.cpp | 94 ---- NorthstarDLL/plugins/pluginbackend.h | 45 -- NorthstarDLL/plugins/plugins.cpp | 581 +++++++++++++-------- NorthstarDLL/plugins/plugins.h | 62 +-- .../scripts/client/scriptserverbrowser.cpp | 2 +- NorthstarDLL/server/serverpresence.cpp | 5 +- NorthstarDLL/server/serverpresence.h | 9 +- NorthstarDLL/shared/gamepresence.cpp | 81 --- NorthstarDLL/shared/gamepresence.h | 48 -- NorthstarDLL/squirrel/squirrel.cpp | 83 +-- NorthstarDLL/squirrel/squirrel.h | 12 +- NorthstarDLL/squirrel/squirrelclasstypes.h | 1 - NorthstarLauncher/main.cpp | 17 + 31 files changed, 571 insertions(+), 892 deletions(-) delete mode 100644 NorthstarDLL/plugins/pluginbackend.cpp delete mode 100644 NorthstarDLL/plugins/pluginbackend.h delete mode 100644 NorthstarDLL/shared/gamepresence.cpp delete mode 100644 NorthstarDLL/shared/gamepresence.h diff --git a/NorthstarDLL/NorthstarDLL.vcxproj b/NorthstarDLL/NorthstarDLL.vcxproj index 464c0b58..a0746bd8 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj +++ b/NorthstarDLL/NorthstarDLL.vcxproj @@ -429,8 +429,8 @@ + - @@ -439,7 +439,6 @@ - @@ -507,7 +506,6 @@ Create Create - @@ -535,7 +533,6 @@ - diff --git a/NorthstarDLL/NorthstarDLL.vcxproj.filters b/NorthstarDLL/NorthstarDLL.vcxproj.filters index 7c6de46e..4530f02d 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj.filters +++ b/NorthstarDLL/NorthstarDLL.vcxproj.filters @@ -1029,6 +1029,9 @@ Header Files\mods + + Header Files\plugins + Header Files\plugins @@ -1059,6 +1062,9 @@ Header Files + + Header Files + Header Files @@ -1152,18 +1158,6 @@ Header Files\scripts - - Header Files\plugins - - - Header Files\plugins - - - Header Files\shared - - - Header Files\util - Header Files\shared @@ -1423,15 +1417,6 @@ Source Files\scripts - - Source Files\plugins - - - Source Files\shared - - - Source Files\util - Source Files\core diff --git a/NorthstarDLL/config/profile.cpp b/NorthstarDLL/config/profile.cpp index d5361efa..08c91208 100644 --- a/NorthstarDLL/config/profile.cpp +++ b/NorthstarDLL/config/profile.cpp @@ -17,6 +17,7 @@ void InitialiseNorthstarPrefix() { int space = cla.find(" "); std::string dirname = cla.substr(9, space - 9); + spdlog::info("Found profile in command line arguments: " + dirname); NORTHSTAR_FOLDER_PREFIX = dirname; } else @@ -25,11 +26,13 @@ void InitialiseNorthstarPrefix() int quote1 = cla.find(quote); int quote2 = (cla.substr(quote1 + 1)).find(quote); std::string dirname = cla.substr(quote1 + 1, quote2); + spdlog::info("Found profile in command line arguments: " + dirname); NORTHSTAR_FOLDER_PREFIX = dirname; } } else { + spdlog::info("Profile was not found in command line arguments. Using default: R2Northstar"); NORTHSTAR_FOLDER_PREFIX = "R2Northstar"; } diff --git a/NorthstarDLL/core/convar/concommand.cpp b/NorthstarDLL/core/convar/concommand.cpp index 82594f04..67c867f8 100644 --- a/NorthstarDLL/core/convar/concommand.cpp +++ b/NorthstarDLL/core/convar/concommand.cpp @@ -2,8 +2,6 @@ #include "shared/misccommands.h" #include "engine/r2engine.h" -#include "plugins/pluginbackend.h" - #include //----------------------------------------------------------------------------- @@ -150,6 +148,4 @@ ON_DLL_LOAD("engine.dll", ConCommand, (CModule module)) { ConCommandConstructor = module.Offset(0x415F60).As(); AddMiscConCommands(); - - g_pPluginCommunicationhandler->m_sEngineData.ConCommandConstructor = ConCommandConstructor; } diff --git a/NorthstarDLL/core/convar/convar.cpp b/NorthstarDLL/core/convar/convar.cpp index d4efc1a0..1ea27fc0 100644 --- a/NorthstarDLL/core/convar/convar.cpp +++ b/NorthstarDLL/core/convar/convar.cpp @@ -3,8 +3,6 @@ #include "convar.h" #include "core/sourceinterface.h" -#include "plugins/pluginbackend.h" - #include typedef void (*ConVarRegisterType)( @@ -39,11 +37,6 @@ ON_DLL_LOAD("engine.dll", ConVar, (CModule module)) R2::g_pCVarInterface = new SourceInterface("vstdlib.dll", "VEngineCvar007"); R2::g_pCVar = *R2::g_pCVarInterface; - - g_pPluginCommunicationhandler->m_sEngineData.conVarMalloc = conVarMalloc; - g_pPluginCommunicationhandler->m_sEngineData.conVarRegister = conVarRegister; - g_pPluginCommunicationhandler->m_sEngineData.ConVar_Vtable = g_pConVar_Vtable; - g_pPluginCommunicationhandler->m_sEngineData.IConVar_Vtable = g_pIConVar_Vtable; } //----------------------------------------------------------------------------- diff --git a/NorthstarDLL/core/hooks.cpp b/NorthstarDLL/core/hooks.cpp index 9124d5af..7c70b0a5 100644 --- a/NorthstarDLL/core/hooks.cpp +++ b/NorthstarDLL/core/hooks.cpp @@ -274,6 +274,8 @@ AUTOHOOK_ABSOLUTEADDR(_GetCommandLineA, GetCommandLineA, LPSTR, WINAPI, ()) return cmdlineOrg; } memcpy(cmdlineModified, args.c_str(), len + 1); + + spdlog::info("Command line: {}", cmdlineModified); } return cmdlineModified; diff --git a/NorthstarDLL/core/math/color.cpp b/NorthstarDLL/core/math/color.cpp index 7b98043a..9936cc5a 100644 --- a/NorthstarDLL/core/math/color.cpp +++ b/NorthstarDLL/core/math/color.cpp @@ -13,8 +13,6 @@ namespace NS::Colors Color RPAK (255, 190, 0 ); Color NORTHSTAR (66 , 72 , 128); Color ECHO (150, 150, 159); - Color PLUGINSYS (244, 60 , 14); - Color PLUGIN (244, 106, 14); Color TRACE (0 , 255, 255); Color DEBUG (0 , 255, 255); diff --git a/NorthstarDLL/core/math/color.h b/NorthstarDLL/core/math/color.h index 76cf8a47..4dc9b36e 100644 --- a/NorthstarDLL/core/math/color.h +++ b/NorthstarDLL/core/math/color.h @@ -186,8 +186,6 @@ namespace NS::Colors extern Color RPAK; extern Color NORTHSTAR; extern Color ECHO; - extern Color PLUGINSYS; - extern Color PLUGIN; extern Color TRACE; extern Color DEBUG; diff --git a/NorthstarDLL/dllmain.cpp b/NorthstarDLL/dllmain.cpp index 6fc49be8..a697da5b 100644 --- a/NorthstarDLL/dllmain.cpp +++ b/NorthstarDLL/dllmain.cpp @@ -7,8 +7,6 @@ #include "plugins/plugins.h" #include "util/version.h" #include "squirrel/squirrel.h" -#include "shared/gamepresence.h" -#include "server/serverpresence.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" @@ -18,6 +16,8 @@ #include #include +typedef void (*initPluginFuncPtr)(void* (*getPluginObject)(PluginObject)); + BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) @@ -32,6 +32,110 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv return TRUE; } +void freeLibrary(HMODULE hLib) +{ + if (!FreeLibrary(hLib)) + { + spdlog::error("There was an error while trying to free library"); + } +} + +bool LoadPlugins() +{ + + std::vector paths; + + std::string pluginPath = GetNorthstarPrefix() + "/plugins"; + if (!fs::exists(pluginPath)) + { + spdlog::warn("Could not find a plugins directory. Skipped loading plugins"); + return false; + } + // ensure dirs exist + fs::recursive_directory_iterator iterator(pluginPath); + if (std::filesystem::begin(iterator) == std::filesystem::end(iterator)) + { + spdlog::warn("Could not find any plugins. Skipped loading plugins"); + return false; + } + for (auto const& entry : iterator) + { + if (fs::is_regular_file(entry) && entry.path().extension() == ".dll") + paths.emplace_back(entry.path().filename()); + } + initGameState(); + for (fs::path path : paths) + { + std::string pathstring = (pluginPath / path).string(); + std::wstring wpath = (pluginPath / path).wstring(); + + LPCWSTR wpptr = wpath.c_str(); + HMODULE datafile = + LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); // Load the DLL as a data file + if (datafile == NULL) + { + spdlog::info("Failed to load library {}: ", std::system_category().message(GetLastError())); + continue; + } + HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(101), MAKEINTRESOURCEW(RT_RCDATA)); + + if (manifestResource == NULL) + { + spdlog::info("Could not find manifest for library {}", pathstring); + freeLibrary(datafile); + continue; + } + spdlog::info("Loading resource from library"); + HGLOBAL myResourceData = LoadResource(datafile, manifestResource); + if (myResourceData == NULL) + { + spdlog::error("Failed to load resource from library"); + freeLibrary(datafile); + continue; + } + int manifestSize = SizeofResource(datafile, manifestResource); + std::string manifest = std::string((const char*)LockResource(myResourceData), 0, manifestSize); + freeLibrary(datafile); + + rapidjson_document manifestJSON; + manifestJSON.Parse(manifest.c_str()); + + if (manifestJSON.HasParseError()) + { + spdlog::error("Manifest for {} was invalid", pathstring); + continue; + } + if (!manifestJSON.HasMember("api_version")) + { + spdlog::error("{} does not have a version number in its manifest", pathstring); + continue; + // spdlog::info(manifestJSON["version"].GetString()); + } + if (strcmp(manifestJSON["api_version"].GetString(), std::to_string(ABI_VERSION).c_str())) + { + spdlog::error("{} has an incompatible API version number in its manifest", pathstring); + continue; + } + // Passed all checks, going to actually load it now + + HMODULE pluginLib = LoadLibraryW(wpptr); // Load the DLL as a data file + if (pluginLib == NULL) + { + spdlog::info("Failed to load library {}: ", std::system_category().message(GetLastError())); + continue; + } + initPluginFuncPtr initPlugin = (initPluginFuncPtr)GetProcAddress(pluginLib, "initializePlugin"); + if (initPlugin == NULL) + { + spdlog::info("Library {} has no function initializePlugin", pathstring); + continue; + } + spdlog::info("Succesfully loaded {}", pathstring); + initPlugin(&getPluginObject); + } + return true; +} + bool InitialiseNorthstar() { static bool bInitialised = false; @@ -40,29 +144,13 @@ bool InitialiseNorthstar() bInitialised = true; - InitialiseNorthstarPrefix(); - // initialise the console if needed (-northstar needs this) InitialiseConsole(); // initialise logging before most other things so that they can use spdlog and it have the proper formatting InitialiseLogging(); - InitialiseVersion(); - CreateLogFiles(); - - InitialiseCrashHandler(); - - // Write launcher version to log - spdlog::info("NorthstarLauncher version: {}", version); - spdlog::info("Command line: {}", GetCommandLineA()); - spdlog::info("Using profile: {}", GetNorthstarPrefix()); - - InstallInitialHooks(); - g_pServerPresence = new ServerPresenceManager(); - - g_pGameStatePresence = new GameStatePresence(); - g_pPluginManager = new PluginManager(); - g_pPluginManager->LoadPlugins(); + InitialiseNorthstarPrefix(); + InitialiseVersion(); InitialiseSquirrelManagers(); @@ -71,6 +159,13 @@ bool InitialiseNorthstar() curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base); + InitialiseCrashHandler(); + InstallInitialHooks(); + CreateLogFiles(); + + // Write launcher version to log + spdlog::info("NorthstarLauncher version: {}", version); + // run callbacks for any libraries that are already loaded by now CallAllPendingDLLLoadCallbacks(); diff --git a/NorthstarDLL/engine/hoststate.cpp b/NorthstarDLL/engine/hoststate.cpp index 50862e99..bd4a242f 100644 --- a/NorthstarDLL/engine/hoststate.cpp +++ b/NorthstarDLL/engine/hoststate.cpp @@ -7,8 +7,6 @@ #include "engine/r2engine.h" #include "shared/exploit_fixes/ns_limits.h" #include "squirrel/squirrel.h" -#include "plugins/plugins.h" -#include "plugins/pluginbackend.h" AUTOHOOK_INIT() @@ -186,8 +184,6 @@ void, __fastcall, (CHostState* self, double flCurrentTime, float flFrameTime)) if (g_pSquirrel->m_pSQVM != nullptr && g_pSquirrel->m_pSQVM->sqvm != nullptr) g_pSquirrel->ProcessMessageBuffer(); - - g_pGameStatePresence->RunFrame(); } ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, (CModule module)) diff --git a/NorthstarDLL/logging/logging.cpp b/NorthstarDLL/logging/logging.cpp index 53795ef0..f88928e1 100644 --- a/NorthstarDLL/logging/logging.cpp +++ b/NorthstarDLL/logging/logging.cpp @@ -28,7 +28,6 @@ namespace NS::log std::shared_ptr echo; std::shared_ptr NORTHSTAR; - std::shared_ptr PLUGINSYS; }; // namespace NS::log // This needs to be called after hooks are loaded so we can access the command line args @@ -149,11 +148,6 @@ void InitialiseConsole() } } -void RegisterLogger(std::shared_ptr logger) -{ - loggers.push_back(logger); -} - void RegisterCustomSink(std::shared_ptr sink) { for (auto& logger : loggers) @@ -195,8 +189,6 @@ void InitialiseLogging() NS::log::rpak = std::make_shared("RPAK_FSYS", NS::Colors::RPAK); NS::log::echo = std::make_shared("ECHO", NS::Colors::ECHO); - NS::log::PLUGINSYS = std::make_shared("PLUGINSYS", NS::Colors::PLUGINSYS); - loggers.push_back(NS::log::SCRIPT_UI); loggers.push_back(NS::log::SCRIPT_CL); loggers.push_back(NS::log::SCRIPT_SV); @@ -206,8 +198,6 @@ void InitialiseLogging() loggers.push_back(NS::log::NATIVE_SV); loggers.push_back(NS::log::NATIVE_EN); - loggers.push_back(NS::log::PLUGINSYS); - loggers.push_back(NS::log::fs); loggers.push_back(NS::log::rpak); loggers.push_back(NS::log::echo); diff --git a/NorthstarDLL/logging/logging.h b/NorthstarDLL/logging/logging.h index 2efee80b..1cfc6644 100644 --- a/NorthstarDLL/logging/logging.h +++ b/NorthstarDLL/logging/logging.h @@ -100,13 +100,10 @@ namespace NS::log extern std::shared_ptr NORTHSTAR; - extern std::shared_ptr PLUGINSYS; - void FlushLoggers(); }; // namespace NS::log void RegisterCustomSink(std::shared_ptr sink); -void RegisterLogger(std::shared_ptr logger); inline bool g_bSpdLog_UseAnsiColor = true; diff --git a/NorthstarDLL/masterserver/masterserver.cpp b/NorthstarDLL/masterserver/masterserver.cpp index 015670e7..d9838484 100644 --- a/NorthstarDLL/masterserver/masterserver.cpp +++ b/NorthstarDLL/masterserver/masterserver.cpp @@ -576,7 +576,7 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* requestThread.detach(); } -void MasterServerManager::AuthenticateWithServer(const char* uid, const char* playerToken, RemoteServerInfo server, const char* password) +void MasterServerManager::AuthenticateWithServer(const char* uid, const char* playerToken, const char* serverId, const char* password) { // dont wait, just stop if we're trying to do 2 auth requests at once if (m_bAuthenticatingWithGameServer) @@ -589,11 +589,11 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl std::string uidStr(uid); std::string tokenStr(playerToken); - std::string serverIdStr(server.id); + std::string serverIdStr(serverId); std::string passwordStr(password); std::thread requestThread( - [this, uidStr, tokenStr, serverIdStr, passwordStr, server]() + [this, uidStr, tokenStr, serverIdStr, passwordStr]() { // esnure that any persistence saving is done, so we know masterserver has newest while (m_bSavingPersistentData) @@ -691,9 +691,6 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl m_bHasPendingConnectionInfo = true; m_bSuccessfullyAuthenticatedWithGameServer = true; - - m_currentServer = server; - m_sCurrentServerPassword = passwordStr; } else { diff --git a/NorthstarDLL/masterserver/masterserver.h b/NorthstarDLL/masterserver/masterserver.h index e87b31a2..623d7d43 100644 --- a/NorthstarDLL/masterserver/masterserver.h +++ b/NorthstarDLL/masterserver/masterserver.h @@ -114,9 +114,6 @@ class MasterServerManager bool m_bHasMainMenuPromoData = false; MainMenuPromoData m_sMainMenuPromoData; - std::optional m_currentServer; - std::string m_sCurrentServerPassword; - std::unordered_set m_handledServerConnections; public: @@ -127,7 +124,7 @@ class MasterServerManager void RequestMainMenuPromos(); void AuthenticateOriginWithMasterServer(const char* uid, const char* originToken); void AuthenticateWithOwnServer(const char* uid, const char* playerToken); - void AuthenticateWithServer(const char* uid, const char* playerToken, RemoteServerInfo server, const char* password); + void AuthenticateWithServer(const char* uid, const char* playerToken, const char* serverId, const char* password); void WritePlayerPersistentData(const char* playerId, const char* pdata, size_t pdataSize); void ProcessConnectionlessPacketSigreq1(std::string req); }; diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index 8ac9ac54..3ec922f4 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -241,11 +241,6 @@ Mod::Mod(fs::path modDir, char* jsonBuf) } } - if (modJson.HasMember("InitScript") && modJson["InitScript"].IsString()) - { - initScript = modJson["InitScript"].GetString(); - } - if (modJson.HasMember("Localisation") && modJson["Localisation"].IsArray()) { for (auto& localisationStr : modJson["Localisation"].GetArray()) diff --git a/NorthstarDLL/mods/modmanager.h b/NorthstarDLL/mods/modmanager.h index a4c72f77..369eb07b 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -103,8 +103,6 @@ class Mod std::vector ConCommands; // custom localisation files created by the mod std::vector LocalisationFiles; - // custom script init.nut - std::string initScript; // other files: diff --git a/NorthstarDLL/pch.h b/NorthstarDLL/pch.h index 9ad8378c..55ebba8b 100644 --- a/NorthstarDLL/pch.h +++ b/NorthstarDLL/pch.h @@ -20,11 +20,6 @@ namespace fs = std::filesystem; -#define EXPORT extern "C" __declspec(dllexport) - -typedef void (*callable)(); -typedef void (*callable_v)(void* v); - // clang-format off #define assert_msg(exp, msg) assert((exp, msg)) //clang-format on @@ -33,7 +28,6 @@ typedef void (*callable_v)(void* v); #include "core/structs.h" #include "core/math/color.h" - #include "spdlog/spdlog.h" #include "logging/logging.h" #include "MinHook.h" diff --git a/NorthstarDLL/plugins/plugin_abi.h b/NorthstarDLL/plugins/plugin_abi.h index c9fa9d25..4b176a32 100644 --- a/NorthstarDLL/plugins/plugin_abi.h +++ b/NorthstarDLL/plugins/plugin_abi.h @@ -1,164 +1,68 @@ #pragma once #include -#include "squirrel/squirrelclasstypes.h" -#define ABI_VERSION 2 - -enum GameState +#define ABI_VERSION 1 +/// +/// This enum is used for referencing the different types of objects we can pass to a plugin +/// Anything exposed to a plugin must not a be C++ type, as they could break when compiling with a different compiler. +/// Any ABI incompatible change must increment the version number. +/// Nothing must be removed from this enum, only appended. When it absolutely necessary to deprecate an object, it should return UNSUPPORTED +/// when retrieved +/// +enum PluginObject { - LOADING = 0, - MAINMENU = 1, - LOBBY = 2, - INGAME = 3 + UNSUPPORTED = 0, + GAMESTATE = 1, + SERVERINFO = 2, + PLAYERINFO = 3, + DUMMY = 0xFFFF }; -enum PluginLoadDLL +enum GameStateInfoType { - ENGINE = 0, - CLIENT, - SERVER + ourScore = 0, + secondHighestScore = 1, + highestScore = 2, + connected = 3, + loading = 4, + map = 5, + mapDisplayName = 6, + playlist = 7, + playlistDisplayName = 8, + players = 9 }; - -enum ObjectType +struct GameState { - CONCOMMANDS = 0, - CONVAR = 1, + int (*getGameStateChar)(char* out_buf, size_t out_buf_len, GameStateInfoType var); + int (*getGameStateInt)(int* out_ptr, GameStateInfoType var); + int (*getGameStateBool)(bool* out_ptr, GameStateInfoType var); }; -struct SquirrelFunctions +enum ServerInfoType { - RegisterSquirrelFuncType RegisterSquirrelFunc; - sq_defconstType __sq_defconst; - - sq_compilebufferType __sq_compilebuffer; - sq_callType __sq_call; - sq_raiseerrorType __sq_raiseerror; - - sq_newarrayType __sq_newarray; - sq_arrayappendType __sq_arrayappend; - - sq_newtableType __sq_newtable; - sq_newslotType __sq_newslot; - - sq_pushroottableType __sq_pushroottable; - sq_pushstringType __sq_pushstring; - sq_pushintegerType __sq_pushinteger; - sq_pushfloatType __sq_pushfloat; - sq_pushboolType __sq_pushbool; - sq_pushassetType __sq_pushasset; - sq_pushvectorType __sq_pushvector; - sq_pushobjectType __sq_pushobject; - sq_getthisentityType __sq_getthisentity; - sq_getobjectType __sq_getobject; - - sq_stackinfosType __sq_stackinfos; - - sq_getstringType __sq_getstring; - sq_getintegerType __sq_getinteger; - sq_getfloatType __sq_getfloat; - sq_getboolType __sq_getbool; - sq_getType __sq_get; - sq_getassetType __sq_getasset; - sq_getuserdataType __sq_getuserdata; - sq_getvectorType __sq_getvector; - - sq_createuserdataType __sq_createuserdata; - sq_setuserdatatypeidType __sq_setuserdatatypeid; - sq_getfunctionType __sq_getfunction; - - sq_schedule_call_externalType __sq_schedule_call_external; - sq_getentityfrominstanceType __sq_getentityfrominstance; - sq_GetEntityConstantType __sq_GetEntityConstant_CBaseEntity; -}; - -struct MessageSource -{ - const char* file; - const char* func; - int line; + id = 0, + name = 1, + description = 2, + password = 3, + maxPlayers = 4, + roundBased = 5, + scoreLimit = 6, + endTime = 7 }; - -// This is a modified version of spdlog::details::log_msg -// This is so that we can make it cross DLL boundaries -struct LogMsg +struct ServerInfo { - int level; - uint64_t timestamp; - const char* msg; - MessageSource source; - int pluginHandle; + int (*getServerInfoChar)(char* out_buf, size_t out_buf_len, ServerInfoType var); + int (*getServerInfoInt)(int* out_ptr, ServerInfoType var); + int (*getServerInfoBool)(bool* out_ptr, ServerInfoType var); }; -typedef void (*loggerfunc_t)(LogMsg* msg); -typedef void (*PLUGIN_RELAY_INVITE_TYPE)(const char* invite); -typedef void* (*CreateObjectFunc)(ObjectType type); - -struct PluginNorthstarData +enum PlayerInfoType { - const char* version; - HMODULE northstarModule; - int pluginHandle; + uid = 0 }; - -struct PluginInitFuncs +struct PlayerInfo { - loggerfunc_t logger; - PLUGIN_RELAY_INVITE_TYPE relayInviteFunc; - CreateObjectFunc createObject; + int (*getPlayerInfoChar)(char* out_buf, size_t out_buf_len, PlayerInfoType var); + int (*getPlayerInfoInt)(int* out_ptr, PlayerInfoType var); + int (*getPlayerInfoBool)(bool* out_ptr, PlayerInfoType var); }; - -struct PluginEngineData -{ - void* ConCommandConstructor; - void* conVarMalloc; - void* conVarRegister; - void* ConVar_Vtable; - void* IConVar_Vtable; -}; - -struct PluginGameStatePresence -{ - const char* id; - const char* name; - const char* description; - const char* password; - - bool isServer; - bool isLocal; - GameState state; - - const char* map; - const char* mapDisplayname; - const char* playlist; - const char* playlistDisplayname; - - int currentPlayers; - int maxPlayers; - - int ownScore; - int otherHighestScore; // NOTE: The highest score OR the second highest score if we have the highest - int maxScore; - - int timestampEnd; -}; - -/// Async communication within the plugin system -/// Due to the asynchronous nature of plugins, combined with the limitations of multi-compiler support -/// and the custom memory allocator used by r2, is it difficult to safely get data across DLL boundaries -/// from Northstar to plugin unless Northstar can own that memory. -/// This means that plugins should manage their own memory and can only receive data from northstar using one of the functions below. -/// These should be exports of the plugin DLL. If they are not exported, they will not be called. -/// Note that it is not required to have these exports if you do not use them. -/// - -// Northstar -> Plugin -typedef void (*PLUGIN_INIT_TYPE)(PluginInitFuncs* funcs, PluginNorthstarData* data); -typedef void (*PLUGIN_INIT_SQVM_TYPE)(SquirrelFunctions* funcs); -typedef void (*PLUGIN_INFORM_SQVM_CREATED_TYPE)(ScriptContext context, CSquirrelVM* sqvm); -typedef void (*PLUGIN_INFORM_SQVM_DESTROYED_TYPE)(ScriptContext context); - -// Async Communication types - -// Northstar -> Plugin -typedef void (*PLUGIN_PUSH_PRESENCE_TYPE)(PluginGameStatePresence* data); -typedef void (*PLUGIN_INFORM_DLL_LOAD_TYPE)(PluginLoadDLL dll, void* data); diff --git a/NorthstarDLL/plugins/pluginbackend.cpp b/NorthstarDLL/plugins/pluginbackend.cpp deleted file mode 100644 index b442d702..00000000 --- a/NorthstarDLL/plugins/pluginbackend.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "pch.h" -#include "pluginbackend.h" -#include "plugin_abi.h" -#include "server/serverpresence.h" -#include "masterserver/masterserver.h" -#include "squirrel/squirrel.h" -#include "plugins.h" - -#include "core/convar/concommand.h" - -#define EXPORT extern "C" __declspec(dllexport) - -AUTOHOOK_INIT() - -PluginCommunicationHandler* g_pPluginCommunicationhandler; - -static PluginDataRequest storedRequest {PluginDataRequestType::END, (PluginRespondDataCallable) nullptr}; - -void init_plugincommunicationhandler() -{ - g_pPluginCommunicationhandler = new PluginCommunicationHandler; - g_pPluginCommunicationhandler->requestQueue = {}; -} - -void PluginCommunicationHandler::RunFrame() -{ - std::lock_guard lock(requestMutex); - if (!requestQueue.empty()) - { - storedRequest = requestQueue.front(); - switch (storedRequest.type) - { - default: - spdlog::error("{} was called with invalid request type '{}'", __FUNCTION__, static_cast(storedRequest.type)); - } - requestQueue.pop(); - } -} - -void PluginCommunicationHandler::PushRequest(PluginDataRequestType type, PluginRespondDataCallable func) -{ - std::lock_guard lock(requestMutex); - requestQueue.push(PluginDataRequest {type, func}); -} - -void PluginCommunicationHandler::GeneratePresenceObjects() -{ - PluginGameStatePresence presence {}; - - presence.id = g_pGameStatePresence->id.c_str(); - presence.name = g_pGameStatePresence->name.c_str(); - presence.description = g_pGameStatePresence->description.c_str(); - presence.password = g_pGameStatePresence->password.c_str(); - - presence.isServer = g_pGameStatePresence->isServer; - presence.isLocal = g_pGameStatePresence->isLocal; - - if (g_pGameStatePresence->isLoading) - presence.state = GameState::LOADING; - else if (g_pGameStatePresence->uiMap == "") - presence.state = GameState::MAINMENU; - else if (g_pGameStatePresence->map == "mp_lobby" && g_pGameStatePresence->isLocal && g_pGameStatePresence->isLobby) - presence.state = GameState::LOBBY; - else - presence.state = GameState::INGAME; - - presence.map = g_pGameStatePresence->map.c_str(); - presence.mapDisplayname = g_pGameStatePresence->mapDisplayname.c_str(); - presence.playlist = g_pGameStatePresence->playlist.c_str(); - presence.playlistDisplayname = g_pGameStatePresence->playlistDisplayname.c_str(); - - presence.currentPlayers = g_pGameStatePresence->currentPlayers; - presence.maxPlayers = g_pGameStatePresence->maxPlayers; - presence.ownScore = g_pGameStatePresence->ownScore; - presence.otherHighestScore = g_pGameStatePresence->otherHighestScore; - presence.maxScore = g_pGameStatePresence->maxScore; - presence.timestampEnd = g_pGameStatePresence->timestampEnd; - g_pPluginManager->PushPresence(&presence); -} - -ON_DLL_LOAD_RELIESON("engine.dll", PluginBackendEngine, ConCommand, (CModule module)) -{ - g_pPluginManager->InformDLLLoad(PluginLoadDLL::ENGINE, &g_pPluginCommunicationhandler->m_sEngineData); -} - -ON_DLL_LOAD_RELIESON("client.dll", PluginBackendClient, ConCommand, (CModule module)) -{ - g_pPluginManager->InformDLLLoad(PluginLoadDLL::CLIENT, nullptr); -} - -ON_DLL_LOAD_RELIESON("server.dll", PluginBackendServer, ConCommand, (CModule module)) -{ - g_pPluginManager->InformDLLLoad(PluginLoadDLL::SERVER, nullptr); -} diff --git a/NorthstarDLL/plugins/pluginbackend.h b/NorthstarDLL/plugins/pluginbackend.h deleted file mode 100644 index ef42c508..00000000 --- a/NorthstarDLL/plugins/pluginbackend.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once -#include "pch.h" -#include "plugin_abi.h" -#include "shared/gamepresence.h" - -#include -#include - -enum PluginDataRequestType -{ - END = 0, -}; - -union PluginRespondDataCallable -{ - // Empty for now - void* UNUSED; -}; - -class PluginDataRequest -{ - public: - PluginDataRequestType type; - PluginRespondDataCallable func; - PluginDataRequest(PluginDataRequestType type, PluginRespondDataCallable func) : type(type), func(func) {} -}; - -class PluginCommunicationHandler -{ - public: - void RunFrame(); - void PushRequest(PluginDataRequestType type, PluginRespondDataCallable func); - - void GeneratePresenceObjects(); - - public: - std::queue requestQueue; - std::mutex requestMutex; - - PluginEngineData m_sEngineData {}; -}; - -void init_plugincommunicationhandler(); - -extern PluginCommunicationHandler* g_pPluginCommunicationhandler; diff --git a/NorthstarDLL/plugins/plugins.cpp b/NorthstarDLL/plugins/plugins.cpp index 6e3ceb5a..47d27da1 100644 --- a/NorthstarDLL/plugins/plugins.cpp +++ b/NorthstarDLL/plugins/plugins.cpp @@ -1,292 +1,421 @@ -#include "plugins.h" -#include "config/profile.h" - #include "squirrel/squirrel.h" #include "plugins.h" #include "masterserver/masterserver.h" #include "core/convar/convar.h" #include "server/serverpresence.h" -#include - -#include "util/version.h" -#include "pluginbackend.h" -#include "util/wininfo.h" -#include "logging/logging.h" -#include "dedicated/dedicated.h" -PluginManager* g_pPluginManager; +#include +#include -void freeLibrary(HMODULE hLib) +/// +/// The data is split into two different representations: one for internal, and one for plugins, for thread safety reasons +/// The struct exposed to plugins contains getter functions for the various data types. +/// We can safely use C++ types like std::string here since these are only ever handled by Northstar internally +/// +struct InternalGameState +{ + int ourScore; + int secondHighestScore; + int highestScore; + + bool connected; + bool loading; + std::string map; + std::string mapDisplayName; + std::string playlist; + std::string playlistDisplayName; + int players; +}; +struct InternalServerInfo +{ + std::string id; + std::string name; + std::string description; + std::string password; + int maxPlayers; + bool roundBased; + int scoreLimit; + int endTime; +}; +// TODO: need to extend this to include current player data like loadouts +struct InternalPlayerInfo +{ + int uid; +}; + +InternalGameState gameState; +InternalServerInfo serverInfo; +InternalPlayerInfo playerInfo; + +GameState gameStateExport; +ServerInfo serverInfoExport; +PlayerInfo playerInfoExport; + +/// +/// We use SRW Locks because plugins will often be running their own thread +/// To ensure thread safety, and to make it difficult to fuck up, we force them to use *our* functions to get data +/// +static SRWLOCK gameStateLock; +static SRWLOCK serverInfoLock; +static SRWLOCK playerInfoLock; + +void* getPluginObject(PluginObject var) { - if (!FreeLibrary(hLib)) + switch (var) { - spdlog::error("There was an error while trying to free library"); + case PluginObject::GAMESTATE: + return &gameStateExport; + case PluginObject::SERVERINFO: + return &serverInfoExport; + case PluginObject::PLAYERINFO: + return &playerInfoExport; + default: + return (void*)-1; } } -EXPORT void PLUGIN_LOG(LogMsg* msg) +void initGameState() { - spdlog::source_loc src {}; - src.filename = msg->source.file; - src.funcname = msg->source.func; - src.line = msg->source.line; - auto&& logger = g_pPluginManager->m_vLoadedPlugins[msg->pluginHandle].logger; - logger->log(src, (spdlog::level::level_enum)msg->level, msg->msg); + // Initalize the Slim Reader / Writer locks + InitializeSRWLock(&gameStateLock); + InitializeSRWLock(&serverInfoLock); + InitializeSRWLock(&playerInfoLock); + + gameStateExport.getGameStateChar = &getGameStateChar; + gameStateExport.getGameStateInt = &getGameStateInt; + gameStateExport.getGameStateBool = &getGameStateBool; + + serverInfoExport.getServerInfoChar = &getServerInfoChar; + serverInfoExport.getServerInfoInt = &getServerInfoInt; + serverInfoExport.getServerInfoBool = &getServerInfoBool; + + playerInfoExport.getPlayerInfoChar = &getPlayerInfoChar; + playerInfoExport.getPlayerInfoInt = &getPlayerInfoInt; + playerInfoExport.getPlayerInfoBool = &getPlayerInfoBool; + + serverInfo.id = ""; + serverInfo.name = ""; + serverInfo.description = ""; + serverInfo.password = ""; + serverInfo.maxPlayers = 0; + gameState.connected = false; + gameState.loading = false; + gameState.map = ""; + gameState.mapDisplayName = ""; + gameState.playlist = ""; + gameState.playlistDisplayName = ""; + gameState.players = 0; + + playerInfo.uid = 123; } -EXPORT void* CreateObject(ObjectType type) +// string gamemode, string gamemodeName, string map, string mapName, bool connected, bool loading +SQRESULT SQ_UpdateGameStateUI(HSquirrelVM* sqvm) { - switch (type) - { - case ObjectType::CONVAR: - return (void*)new ConVar; - case ObjectType::CONCOMMANDS: - return (void*)new ConCommand; - default: - return NULL; - } + AcquireSRWLockExclusive(&gameStateLock); + gameState.map = g_pSquirrel->getstring(sqvm, 1); + gameState.mapDisplayName = g_pSquirrel->getstring(sqvm, 2); + gameState.playlist = g_pSquirrel->getstring(sqvm, 3); + gameState.playlistDisplayName = g_pSquirrel->getstring(sqvm, 4); + gameState.connected = g_pSquirrel->getbool(sqvm, 5); + gameState.loading = g_pSquirrel->getbool(sqvm, 6); + ReleaseSRWLockExclusive(&gameStateLock); + return SQRESULT_NOTNULL; } -std::optional PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* funcs, PluginNorthstarData* data) +// int playerCount, int outScore, int secondHighestScore, int highestScore, bool roundBased, int scoreLimit +SQRESULT SQ_UpdateGameStateClient(HSquirrelVM* sqvm) { + AcquireSRWLockExclusive(&gameStateLock); + AcquireSRWLockExclusive(&serverInfoLock); + gameState.players = g_pSquirrel->getinteger(sqvm, 1); + serverInfo.maxPlayers = g_pSquirrel->getinteger(sqvm, 2); + gameState.ourScore = g_pSquirrel->getinteger(sqvm, 3); + gameState.secondHighestScore = g_pSquirrel->getinteger(sqvm, 4); + gameState.highestScore = g_pSquirrel->getinteger(sqvm, 5); + serverInfo.roundBased = g_pSquirrel->getbool(sqvm, 6); + serverInfo.scoreLimit = g_pSquirrel->getbool(sqvm, 7); + ReleaseSRWLockExclusive(&gameStateLock); + ReleaseSRWLockExclusive(&serverInfoLock); + return SQRESULT_NOTNULL; +} - Plugin plugin {}; +// string id, string name, string password, int players, int maxPlayers, string map, string mapDisplayName, string playlist, string +// playlistDisplayName +SQRESULT SQ_UpdateServerInfo(HSquirrelVM* sqvm) +{ + AcquireSRWLockExclusive(&gameStateLock); + AcquireSRWLockExclusive(&serverInfoLock); + serverInfo.id = g_pSquirrel->getstring(sqvm, 1); + serverInfo.name = g_pSquirrel->getstring(sqvm, 2); + serverInfo.password = g_pSquirrel->getstring(sqvm, 3); + gameState.players = g_pSquirrel->getinteger(sqvm, 4); + serverInfo.maxPlayers = g_pSquirrel->getinteger(sqvm, 5); + gameState.map = g_pSquirrel->getstring(sqvm, 6); + gameState.mapDisplayName = g_pSquirrel->getstring(sqvm, 7); + gameState.playlist = g_pSquirrel->getstring(sqvm, 8); + gameState.playlistDisplayName = g_pSquirrel->getstring(sqvm, 9); + ReleaseSRWLockExclusive(&gameStateLock); + ReleaseSRWLockExclusive(&serverInfoLock); + return SQRESULT_NOTNULL; +} - std::string pathstring = (pluginPath / path).string(); - std::wstring wpath = (pluginPath / path).wstring(); +// int maxPlayers +SQRESULT SQ_UpdateServerInfoBetweenRounds(HSquirrelVM* sqvm) +{ + AcquireSRWLockExclusive(&serverInfoLock); + serverInfo.id = g_pSquirrel->getstring(sqvm, 1); + serverInfo.name = g_pSquirrel->getstring(sqvm, 2); + serverInfo.password = g_pSquirrel->getstring(sqvm, 3); + serverInfo.maxPlayers = g_pSquirrel->getinteger(sqvm, 4); + ReleaseSRWLockExclusive(&serverInfoLock); + return SQRESULT_NOTNULL; +} - LPCWSTR wpptr = wpath.c_str(); - HMODULE datafile = LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); // Load the DLL as a data file - if (datafile == NULL) - { - NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError())); - return std::nullopt; - } - HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(IDR_RCDATA1), MAKEINTRESOURCEW(RT_RCDATA)); +// float timeInFuture +SQRESULT SQ_UpdateTimeInfo(HSquirrelVM* sqvm) +{ + AcquireSRWLockExclusive(&serverInfoLock); + serverInfo.endTime = ceil(g_pSquirrel->getfloat(sqvm, 1)); + ReleaseSRWLockExclusive(&serverInfoLock); + return SQRESULT_NOTNULL; +} - if (manifestResource == NULL) - { - NS::log::PLUGINSYS->info("Could not find manifest for library '{}'", pathstring); - freeLibrary(datafile); - return std::nullopt; - } - HGLOBAL myResourceData = LoadResource(datafile, manifestResource); - if (myResourceData == NULL) - { - NS::log::PLUGINSYS->error("Failed to load manifest from library '{}'", pathstring); - freeLibrary(datafile); - return std::nullopt; - } - int manifestSize = SizeofResource(datafile, manifestResource); - std::string manifest = std::string((const char*)LockResource(myResourceData), 0, manifestSize); - freeLibrary(datafile); +// bool loading +SQRESULT SQ_SetConnected(HSquirrelVM* sqvm) +{ + AcquireSRWLockExclusive(&gameStateLock); + gameState.loading = g_pSquirrel->getbool(sqvm, 1); + ReleaseSRWLockExclusive(&gameStateLock); + return SQRESULT_NOTNULL; +} - rapidjson_document manifestJSON; - manifestJSON.Parse(manifest.c_str()); +SQRESULT SQ_UpdateListenServer(HSquirrelVM* sqvm) +{ + AcquireSRWLockExclusive(&serverInfoLock); + serverInfo.id = g_pMasterServerManager->m_sOwnServerId; + serverInfo.password = ""; // g_pServerPresence->Cvar_ns_server_password->GetString(); todo this fr + ReleaseSRWLockExclusive(&serverInfoLock); + return SQRESULT_NOTNULL; +} - if (manifestJSON.HasParseError()) - { - NS::log::PLUGINSYS->error("Manifest for '{}' was invalid", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("name")) - { - NS::log::PLUGINSYS->error("'{}' is missing a name in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("displayname")) - { - NS::log::PLUGINSYS->error("'{}' is missing a displayname in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("description")) - { - NS::log::PLUGINSYS->error("'{}' is missing a description in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("api_version")) - { - NS::log::PLUGINSYS->error("'{}' is missing a api_version in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("version")) - { - NS::log::PLUGINSYS->error("'{}' is missing a version in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("run_on_server")) - { - NS::log::PLUGINSYS->error("'{}' is missing 'run_on_server' in its manifest", pathstring); - return std::nullopt; - } - if (!manifestJSON.HasMember("run_on_client")) - { - NS::log::PLUGINSYS->error("'{}' is missing 'run_on_client' in its manifest", pathstring); - return std::nullopt; - } - auto test = manifestJSON["api_version"].GetString(); - if (strcmp(manifestJSON["api_version"].GetString(), std::to_string(ABI_VERSION).c_str())) +int getServerInfoChar(char* out_buf, size_t out_buf_len, ServerInfoType var) +{ + AcquireSRWLockShared(&serverInfoLock); + int n = 0; + switch (var) { - NS::log::PLUGINSYS->error( - "'{}' has an incompatible API version number '{}' in its manifest. Current ABI version is '{}'", pathstring, ABI_VERSION); - return std::nullopt; + case ServerInfoType::id: + strncpy(out_buf, serverInfo.id.c_str(), out_buf_len); + break; + case ServerInfoType::name: + strncpy(out_buf, serverInfo.name.c_str(), out_buf_len); + break; + case ServerInfoType::description: + strncpy(out_buf, serverInfo.id.c_str(), out_buf_len); + break; + case ServerInfoType::password: + strncpy(out_buf, serverInfo.password.c_str(), out_buf_len); + break; + default: + n = -1; } - // Passed all checks, going to actually load it now - HMODULE pluginLib = LoadLibraryW(wpptr); // Load the DLL as a data file - if (pluginLib == NULL) - { - NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError())); - return std::nullopt; - } - plugin.init = (PLUGIN_INIT_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT"); - if (plugin.init == NULL) + ReleaseSRWLockShared(&serverInfoLock); + + return n; +} +int getServerInfoInt(int* out_ptr, ServerInfoType var) +{ + AcquireSRWLockShared(&serverInfoLock); + int n = 0; + switch (var) { - NS::log::PLUGINSYS->info("Library '{}' has no function 'PLUGIN_INIT'", pathstring); - return std::nullopt; + case ServerInfoType::maxPlayers: + *out_ptr = serverInfo.maxPlayers; + break; + case ServerInfoType::scoreLimit: + *out_ptr = serverInfo.scoreLimit; + break; + case ServerInfoType::endTime: + *out_ptr = serverInfo.endTime; + break; + default: + n = -1; } - NS::log::PLUGINSYS->info("Succesfully loaded {}", pathstring); - plugin.name = manifestJSON["name"].GetString(); - plugin.displayName = manifestJSON["displayname"].GetString(); - plugin.description = manifestJSON["description"].GetString(); - plugin.api_version = manifestJSON["api_version"].GetString(); - plugin.version = manifestJSON["version"].GetString(); + ReleaseSRWLockShared(&serverInfoLock); - plugin.run_on_client = manifestJSON["run_on_client"].GetBool(); - plugin.run_on_server = manifestJSON["run_on_server"].GetBool(); - - if (!plugin.run_on_server && IsDedicatedServer()) - return std::nullopt; - - if (manifestJSON.HasMember("dependencyName")) - { - plugin.dependencyName = manifestJSON["dependencyName"].GetString(); - } - else + return n; +} +int getServerInfoBool(bool* out_ptr, ServerInfoType var) +{ + AcquireSRWLockShared(&serverInfoLock); + int n = 0; + switch (var) { - plugin.dependencyName = plugin.name; + case ServerInfoType::roundBased: + *out_ptr = serverInfo.roundBased; + break; + default: + n = -1; } - plugin.init_sqvm_client = (PLUGIN_INIT_SQVM_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT_SQVM_CLIENT"); - plugin.init_sqvm_server = (PLUGIN_INIT_SQVM_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT_SQVM_SERVER"); - plugin.inform_sqvm_created = (PLUGIN_INFORM_SQVM_CREATED_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_SQVM_CREATED"); - plugin.inform_sqvm_destroyed = (PLUGIN_INFORM_SQVM_DESTROYED_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_SQVM_DESTROYED"); - - plugin.push_presence = (PLUGIN_PUSH_PRESENCE_TYPE)GetProcAddress(pluginLib, "PLUGIN_RECEIVE_PRESENCE"); - - plugin.inform_dll_load = (PLUGIN_INFORM_DLL_LOAD_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_DLL_LOAD"); + ReleaseSRWLockShared(&serverInfoLock); - plugin.handle = m_vLoadedPlugins.size(); - plugin.logger = std::make_shared(plugin.displayName.c_str(), NS::Colors::PLUGIN); - RegisterLogger(plugin.logger); - NS::log::PLUGINSYS->info("Loading plugin {} version {}", plugin.displayName, plugin.version); - m_vLoadedPlugins.push_back(plugin); - - plugin.init(funcs, data); - - return plugin; + return n; } -bool PluginManager::LoadPlugins() +int getGameStateChar(char* out_buf, size_t out_buf_len, GameStateInfoType var) { - std::vector paths; - - pluginPath = GetNorthstarPrefix() + "/plugins"; - - PluginNorthstarData data {}; - std::string ns_version {version}; - - PluginInitFuncs funcs {}; - funcs.logger = PLUGIN_LOG; - funcs.relayInviteFunc = nullptr; - funcs.createObject = CreateObject; - - init_plugincommunicationhandler(); - - data.version = ns_version.c_str(); - data.northstarModule = g_NorthstarModule; - - if (!fs::exists(pluginPath)) - { - NS::log::PLUGINSYS->warn("Could not find a plugins directory. Skipped loading plugins"); - return false; - } - // ensure dirs exist - fs::recursive_directory_iterator iterator(pluginPath); - if (std::filesystem::begin(iterator) == std::filesystem::end(iterator)) - { - NS::log::PLUGINSYS->warn("Could not find any plugins. Skipped loading plugins"); - return false; - } - for (auto const& entry : iterator) + AcquireSRWLockShared(&gameStateLock); + int n = 0; + switch (var) { - if (fs::is_regular_file(entry) && entry.path().extension() == ".dll") - paths.emplace_back(entry.path().filename()); + case GameStateInfoType::map: + strncpy(out_buf, gameState.map.c_str(), out_buf_len); + break; + case GameStateInfoType::mapDisplayName: + strncpy(out_buf, gameState.mapDisplayName.c_str(), out_buf_len); + break; + case GameStateInfoType::playlist: + strncpy(out_buf, gameState.playlist.c_str(), out_buf_len); + break; + case GameStateInfoType::playlistDisplayName: + strncpy(out_buf, gameState.playlistDisplayName.c_str(), out_buf_len); + break; + default: + n = -1; } - for (fs::path path : paths) + + ReleaseSRWLockShared(&gameStateLock); + + return n; +} +int getGameStateInt(int* out_ptr, GameStateInfoType var) +{ + AcquireSRWLockShared(&gameStateLock); + int n = 0; + switch (var) { - if (LoadPlugin(path, &funcs, &data)) - data.pluginHandle += 1; + case GameStateInfoType::ourScore: + *out_ptr = gameState.ourScore; + break; + case GameStateInfoType::secondHighestScore: + *out_ptr = gameState.secondHighestScore; + break; + case GameStateInfoType::highestScore: + *out_ptr = gameState.highestScore; + break; + case GameStateInfoType::players: + *out_ptr = gameState.players; + break; + default: + n = -1; } - return true; -} -void PluginManager::InformSQVMLoad(ScriptContext context, SquirrelFunctions* s) + ReleaseSRWLockShared(&gameStateLock); + + return n; +} +int getGameStateBool(bool* out_ptr, GameStateInfoType var) { - for (auto plugin : m_vLoadedPlugins) + AcquireSRWLockShared(&gameStateLock); + int n = 0; + switch (var) { - if (context == ScriptContext::CLIENT && plugin.init_sqvm_client != NULL) - { - plugin.init_sqvm_client(s); - } - else if (context == ScriptContext::SERVER && plugin.init_sqvm_server != NULL) - { - plugin.init_sqvm_server(s); - } + case GameStateInfoType::connected: + *out_ptr = gameState.connected; + break; + case GameStateInfoType::loading: + *out_ptr = gameState.loading; + break; + default: + n = -1; } + + ReleaseSRWLockShared(&gameStateLock); + + return n; } -void PluginManager::InformSQVMCreated(ScriptContext context, CSquirrelVM* sqvm) +int getPlayerInfoChar(char* out_buf, size_t out_buf_len, PlayerInfoType var) { - for (auto plugin : m_vLoadedPlugins) + AcquireSRWLockShared(&playerInfoLock); + int n = 0; + switch (var) { - if (plugin.inform_sqvm_created != NULL) - { - plugin.inform_sqvm_created(context, sqvm); - } + default: + n = -1; } -} -void PluginManager::InformSQVMDestroyed(ScriptContext context) + ReleaseSRWLockShared(&playerInfoLock); + + return n; +} +int getPlayerInfoInt(int* out_ptr, PlayerInfoType var) { - for (auto plugin : m_vLoadedPlugins) + AcquireSRWLockShared(&playerInfoLock); + int n = 0; + switch (var) { - if (plugin.inform_sqvm_destroyed != NULL) - { - plugin.inform_sqvm_destroyed(context); - } + case PlayerInfoType::uid: + *out_ptr = playerInfo.uid; + break; + default: + n = -1; } -} -void PluginManager::PushPresence(PluginGameStatePresence* data) + ReleaseSRWLockShared(&playerInfoLock); + + return n; +} +int getPlayerInfoBool(bool* out_ptr, PlayerInfoType var) { - for (auto plugin : m_vLoadedPlugins) + AcquireSRWLockShared(&playerInfoLock); + int n = 0; + switch (var) { - if (plugin.push_presence != NULL) - { - plugin.push_presence(data); - } + default: + n = -1; } + + ReleaseSRWLockShared(&playerInfoLock); + + return n; } -void PluginManager::InformDLLLoad(PluginLoadDLL dll, void* data) +ON_DLL_LOAD_CLIENT_RELIESON("client.dll", PluginCommands, ClientSquirrel, (CModule module)) { - for (auto plugin : m_vLoadedPlugins) + // i swear there's a way to make this not have be run in 2 contexts but i can't figure it out + // some funcs i need are just not available in UI or CLIENT + + if (g_pSquirrel && g_pSquirrel) { - if (plugin.inform_dll_load != NULL) - { - plugin.inform_dll_load(dll, data); - } + g_pSquirrel->AddFuncRegistration( + "void", + "NSUpdateGameStateUI", + "string gamemode, string gamemodeName, string map, string mapName, bool connected, bool loading", + "", + SQ_UpdateGameStateUI); + g_pSquirrel->AddFuncRegistration( + "void", + "NSUpdateGameStateClient", + "int playerCount, int maxPlayers, int outScore, int secondHighestScore, int highestScore, bool roundBased, int scoreLimit", + "", + SQ_UpdateGameStateClient); + g_pSquirrel->AddFuncRegistration( + "void", + "NSUpdateServerInfo", + "string id, string name, string password, int players, int maxPlayers, string map, string mapDisplayName, string playlist, " + "string " + "playlistDisplayName", + "", + SQ_UpdateServerInfo); + g_pSquirrel->AddFuncRegistration( + "void", "NSUpdateServerInfoReload", "int maxPlayers", "", SQ_UpdateServerInfoBetweenRounds); + g_pSquirrel->AddFuncRegistration("void", "NSUpdateTimeInfo", "float timeInFuture", "", SQ_UpdateTimeInfo); + g_pSquirrel->AddFuncRegistration("void", "NSSetLoading", "bool loading", "", SQ_SetConnected); + g_pSquirrel->AddFuncRegistration("void", "NSUpdateListenServer", "", "", SQ_UpdateListenServer); } } diff --git a/NorthstarDLL/plugins/plugins.h b/NorthstarDLL/plugins/plugins.h index ffa277d0..953801a2 100644 --- a/NorthstarDLL/plugins/plugins.h +++ b/NorthstarDLL/plugins/plugins.h @@ -1,57 +1,17 @@ #pragma once #include "plugin_abi.h" -const int IDR_RCDATA1 = 101; +int getServerInfoChar(char* out_buf, size_t out_buf_len, ServerInfoType var); +int getServerInfoInt(int* out_ptr, ServerInfoType var); +int getServerInfoBool(bool* out_ptr, ServerInfoType var); -class Plugin -{ - public: - std::string name; - std::string displayName; - std::string dependencyName; - std::string description; +int getGameStateChar(char* out_buf, size_t out_buf_len, GameStateInfoType var); +int getGameStateInt(int* out_ptr, GameStateInfoType var); +int getGameStateBool(bool* out_ptr, GameStateInfoType var); - std::string api_version; - std::string version; +int getPlayerInfoChar(char* out_buf, size_t out_buf_len, PlayerInfoType var); +int getPlayerInfoInt(int* out_ptr, PlayerInfoType var); +int getPlayerInfoBool(bool* out_ptr, PlayerInfoType var); - // For now this is just implemented as the index into the plugins array - // Maybe a bit shit but it works - int handle; - - std::shared_ptr logger; - - bool run_on_client = false; - bool run_on_server = false; - - public: - PLUGIN_INIT_TYPE init; - PLUGIN_INIT_SQVM_TYPE init_sqvm_client; - PLUGIN_INIT_SQVM_TYPE init_sqvm_server; - PLUGIN_INFORM_SQVM_CREATED_TYPE inform_sqvm_created; - PLUGIN_INFORM_SQVM_DESTROYED_TYPE inform_sqvm_destroyed; - - PLUGIN_PUSH_PRESENCE_TYPE push_presence; - PLUGIN_INFORM_DLL_LOAD_TYPE inform_dll_load; -}; - -class PluginManager -{ - public: - std::vector m_vLoadedPlugins; - - public: - bool LoadPlugins(); - std::optional LoadPlugin(fs::path path, PluginInitFuncs* funcs, PluginNorthstarData* data); - - void InformSQVMLoad(ScriptContext context, SquirrelFunctions* s); - void InformSQVMCreated(ScriptContext context, CSquirrelVM* sqvm); - void InformSQVMDestroyed(ScriptContext context); - void PushPresence(PluginGameStatePresence* data); - - void InformDLLLoad(PluginLoadDLL dll, void* data); - - private: - std::string pluginPath; -}; - -extern PluginManager* g_pPluginManager; +void initGameState(); +void* getPluginObject(PluginObject var); diff --git a/NorthstarDLL/scripts/client/scriptserverbrowser.cpp b/NorthstarDLL/scripts/client/scriptserverbrowser.cpp index 39279de5..584ec905 100644 --- a/NorthstarDLL/scripts/client/scriptserverbrowser.cpp +++ b/NorthstarDLL/scripts/client/scriptserverbrowser.cpp @@ -336,7 +336,7 @@ ADD_SQFUNC("void", NSTryAuthWithServer, "int serverIndex, string password = ''", g_pMasterServerManager->AuthenticateWithServer( R2::g_pLocalPlayerUserID, g_pMasterServerManager->m_sOwnClientAuthToken, - g_pMasterServerManager->m_vRemoteServers[serverIndex], + g_pMasterServerManager->m_vRemoteServers[serverIndex].id, (char*)password); return SQRESULT_NULL; diff --git a/NorthstarDLL/server/serverpresence.cpp b/NorthstarDLL/server/serverpresence.cpp index 945f5810..c7ef20c3 100644 --- a/NorthstarDLL/server/serverpresence.cpp +++ b/NorthstarDLL/server/serverpresence.cpp @@ -71,7 +71,7 @@ std::string UnescapeUnicode(const std::string& str) return result; } -void ServerPresenceManager::CreateConVars() +ServerPresenceManager::ServerPresenceManager() { // clang-format off // register convars @@ -223,6 +223,7 @@ void ServerPresenceManager::SetPlayerCount(const int iPlayerCount) ON_DLL_LOAD_RELIESON("engine.dll", ServerPresence, ConVar, (CModule module)) { - g_pServerPresence->CreateConVars(); + g_pServerPresence = new ServerPresenceManager; + Cvar_hostname = module.Offset(0x1315BAE8).Deref().As(); } diff --git a/NorthstarDLL/server/serverpresence.h b/NorthstarDLL/server/serverpresence.h index 3aabecde..6b8c2859 100644 --- a/NorthstarDLL/server/serverpresence.h +++ b/NorthstarDLL/server/serverpresence.h @@ -3,11 +3,8 @@ struct ServerPresence { - public: int m_iPort; - std::string m_sServerId; - std::string m_sServerName; std::string m_sServerDesc; char m_Password[256]; // probably bigger than will ever be used in practice, lol @@ -28,8 +25,6 @@ struct ServerPresence { m_iPort = obj->m_iPort; - m_sServerId = obj->m_sServerId; - m_sServerName = obj->m_sServerName; m_sServerDesc = obj->m_sServerDesc; memcpy(m_Password, obj->m_Password, sizeof(m_Password)); @@ -72,9 +67,9 @@ class ServerPresenceManager ConVar* Cvar_ns_report_sp_server_to_masterserver; public: - void AddPresenceReporter(ServerPresenceReporter* reporter); + ServerPresenceManager(); - void CreateConVars(); + void AddPresenceReporter(ServerPresenceReporter* reporter); void CreatePresence(); void DestroyPresence(); diff --git a/NorthstarDLL/shared/gamepresence.cpp b/NorthstarDLL/shared/gamepresence.cpp deleted file mode 100644 index 86a87526..00000000 --- a/NorthstarDLL/shared/gamepresence.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "pch.h" - -#include "gamepresence.h" -#include "plugins/pluginbackend.h" -#include "plugins/plugins.h" -#include "dedicated/dedicated.h" -#include "server/serverpresence.h" -#include "masterserver/masterserver.h" -#include "squirrel/squirrel.h" - -GameStatePresence* g_pGameStatePresence; - -GameStatePresence::GameStatePresence() -{ - g_pServerPresence->AddPresenceReporter(&m_GameStateServerPresenceReporter); -} - -void GameStateServerPresenceReporter::RunFrame(double flCurrentTime, const ServerPresence* pServerPresence) -{ - g_pGameStatePresence->id = pServerPresence->m_sServerId; - g_pGameStatePresence->name = pServerPresence->m_sServerName; - g_pGameStatePresence->description = pServerPresence->m_sServerDesc; - g_pGameStatePresence->password = pServerPresence->m_Password; - - g_pGameStatePresence->map = pServerPresence->m_MapName; - g_pGameStatePresence->playlist = pServerPresence->m_PlaylistName; - g_pGameStatePresence->currentPlayers = pServerPresence->m_iPlayerCount; - g_pGameStatePresence->maxPlayers = pServerPresence->m_iMaxPlayers; - - g_pGameStatePresence->isLocal = !IsDedicatedServer(); -} - -void GameStatePresence::RunFrame() -{ - if (g_pSquirrel->m_pSQVM != nullptr && g_pSquirrel->m_pSQVM->sqvm != nullptr) - g_pSquirrel->Call("NorthstarCodeCallback_GenerateUIPresence"); - - if (g_pSquirrel->m_pSQVM != nullptr && g_pSquirrel->m_pSQVM->sqvm != nullptr) - { - auto test = g_pSquirrel->Call("NorthstarCodeCallback_GenerateGameState"); - } - g_pPluginCommunicationhandler->GeneratePresenceObjects(); -} - -ADD_SQFUNC("void", NSPushGameStateData, "GameStateStruct gamestate", "", ScriptContext::CLIENT) -{ - SQStructInstance* structInst = g_pSquirrel->m_pSQVM->sqvm->_stackOfCurrentFunction[1]._VAL.asStructInstance; - g_pGameStatePresence->map = structInst->data[0]._VAL.asString->_val; - g_pGameStatePresence->mapDisplayname = structInst->data[1]._VAL.asString->_val; - g_pGameStatePresence->playlist = structInst->data[2]._VAL.asString->_val; - g_pGameStatePresence->playlistDisplayname = structInst->data[3]._VAL.asString->_val; - - g_pGameStatePresence->currentPlayers = structInst->data[4]._VAL.asInteger; - g_pGameStatePresence->maxPlayers = structInst->data[5]._VAL.asInteger; - g_pGameStatePresence->ownScore = structInst->data[6]._VAL.asInteger; - g_pGameStatePresence->otherHighestScore = structInst->data[7]._VAL.asInteger; - g_pGameStatePresence->maxScore = structInst->data[8]._VAL.asInteger; - g_pGameStatePresence->timestampEnd = ceil(structInst->data[9]._VAL.asFloat); - - if (g_pMasterServerManager->m_currentServer) - { - g_pGameStatePresence->id = g_pMasterServerManager->m_currentServer->id; - g_pGameStatePresence->name = g_pMasterServerManager->m_currentServer->name; - g_pGameStatePresence->description = g_pMasterServerManager->m_currentServer->description; - g_pGameStatePresence->password = g_pMasterServerManager->m_sCurrentServerPassword; - } - - return SQRESULT_NOTNULL; -} - -ADD_SQFUNC("void", NSPushUIPresence, "UIPresenceStruct presence", "", ScriptContext::UI) -{ - SQStructInstance* structInst = g_pSquirrel->m_pSQVM->sqvm->_stackOfCurrentFunction[1]._VAL.asStructInstance; - - g_pGameStatePresence->isLoading = structInst->data[0]._VAL.asInteger; - g_pGameStatePresence->isLobby = structInst->data[1]._VAL.asInteger; - g_pGameStatePresence->loadingLevel = structInst->data[2]._VAL.asString->_val; - g_pGameStatePresence->uiMap = structInst->data[3]._VAL.asString->_val; - - return SQRESULT_NOTNULL; -} diff --git a/NorthstarDLL/shared/gamepresence.h b/NorthstarDLL/shared/gamepresence.h deleted file mode 100644 index 167f83ab..00000000 --- a/NorthstarDLL/shared/gamepresence.h +++ /dev/null @@ -1,48 +0,0 @@ - -#pragma once -#include "pch.h" -#include "server/serverpresence.h" - -class GameStateServerPresenceReporter : public ServerPresenceReporter -{ - void RunFrame(double flCurrentTime, const ServerPresence* pServerPresence); -}; - -class GameStatePresence -{ - public: - std::string id; - std::string name; - std::string description; - std::string password; // NOTE: May be empty - - bool isServer; - bool isLocal = false; - bool isLoading; - bool isLobby; - std::string loadingLevel; - - std::string uiMap; - - std::string map; - std::string mapDisplayname; - std::string playlist; - std::string playlistDisplayname; - - int currentPlayers; - int maxPlayers; - - int ownScore; - int otherHighestScore; // NOTE: The highest score OR the second highest score if we have the highest - int maxScore; - - int timestampEnd; - - GameStatePresence(); - void RunFrame(); - - protected: - GameStateServerPresenceReporter m_GameStateServerPresenceReporter; -}; - -extern GameStatePresence* g_pGameStatePresence; diff --git a/NorthstarDLL/squirrel/squirrel.cpp b/NorthstarDLL/squirrel/squirrel.cpp index 62287245..21ce9ae0 100644 --- a/NorthstarDLL/squirrel/squirrel.cpp +++ b/NorthstarDLL/squirrel/squirrel.cpp @@ -5,8 +5,6 @@ #include "dedicated/dedicated.h" #include "engine/r2engine.h" #include "core/tier0.h" -#include "plugins/plugin_abi.h" -#include "plugins/plugins.h" #include @@ -154,52 +152,6 @@ const char* SQTypeNameFromID(int type) return ""; } -template void SquirrelManager::GenerateSquirrelFunctionsStruct(SquirrelFunctions* s) -{ - s->RegisterSquirrelFunc = RegisterSquirrelFunc; - s->__sq_defconst = __sq_defconst; - - s->__sq_compilebuffer = __sq_compilebuffer; - s->__sq_call = __sq_call; - s->__sq_raiseerror = __sq_raiseerror; - - s->__sq_newarray = __sq_newarray; - s->__sq_arrayappend = __sq_arrayappend; - - s->__sq_newtable = __sq_newtable; - s->__sq_newslot = __sq_newslot; - - s->__sq_pushroottable = __sq_pushroottable; - s->__sq_pushstring = __sq_pushstring; - s->__sq_pushinteger = __sq_pushinteger; - s->__sq_pushfloat = __sq_pushfloat; - s->__sq_pushbool = __sq_pushbool; - s->__sq_pushasset = __sq_pushasset; - s->__sq_pushvector = __sq_pushvector; - s->__sq_pushobject = __sq_pushobject; - s->__sq_getstring = __sq_getstring; - s->__sq_getthisentity = __sq_getthisentity; - s->__sq_getobject = __sq_getobject; - - s->__sq_stackinfos = __sq_stackinfos; - - s->__sq_getinteger = __sq_getinteger; - s->__sq_getfloat = __sq_getfloat; - s->__sq_getbool = __sq_getbool; - s->__sq_get = __sq_get; - s->__sq_getasset = __sq_getasset; - s->__sq_getuserdata = __sq_getuserdata; - s->__sq_getvector = __sq_getvector; - s->__sq_createuserdata = __sq_createuserdata; - s->__sq_setuserdatatypeid = __sq_setuserdatatypeid; - s->__sq_getfunction = __sq_getfunction; - - s->__sq_getentityfrominstance = __sq_getentityfrominstance; - s->__sq_GetEntityConstant_CBaseEntity = __sq_GetEntityConstant_CBaseEntity; - - s->__sq_schedule_call_external = AsyncCall_External; -} - // Allows for generating squirrelmessages from plugins. // Not used in this version, but will be used later void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function) @@ -256,7 +208,6 @@ template void SquirrelManager::VMCreated(CSquir defconst(m_pSQVM, pair.first.c_str(), bWasFound); } g_pSquirrel->messageBuffer = new SquirrelMessageBuffer(); - g_pPluginManager->InformSQVMCreated(context, newSqvm); } template void SquirrelManager::VMDestroyed() @@ -284,8 +235,6 @@ template void SquirrelManager::VMDestroyed() } } - g_pPluginManager->InformSQVMDestroyed(context); - // Discard the previous vm and delete the message buffer. m_pSQVM = nullptr; @@ -409,23 +358,6 @@ template CSquirrelVM* __fastcall CreateNewVMHook(void* a return sqvm; } -template bool (*__fastcall CSquirrelVM_init)(CSquirrelVM* vm, ScriptContext realContext, float time); -template bool __fastcall CSquirrelVM_initHook(CSquirrelVM* vm, ScriptContext realContext, float time) -{ - bool ret = CSquirrelVM_init(vm, realContext, time); - for (Mod mod : g_pModManager->m_LoadedMods) - { - if (mod.initScript.size() != 0) - { - std::string name = mod.initScript.substr(mod.initScript.find_last_of('/') + 1); - std::string path = std::string("scripts/vscripts/") + mod.initScript; - if (g_pSquirrel->compilefile(vm, path.c_str(), name.c_str(), 0)) - g_pSquirrel->compilefile(vm, path.c_str(), name.c_str(), 1); - } - } - return ret; -} - template void (*__fastcall DestroyVM)(void* a1, CSquirrelVM* sqvm); template void __fastcall DestroyVMHook(void* a1, CSquirrelVM* sqvm) { @@ -706,10 +638,8 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_compilebuffer = module.Offset(0x3110).As(); g_pSquirrel->__sq_pushroottable = module.Offset(0x5860).As(); - g_pSquirrel->__sq_compilefile = module.Offset(0xF950).As(); g_pSquirrel->__sq_compilebuffer = g_pSquirrel->__sq_compilebuffer; g_pSquirrel->__sq_pushroottable = g_pSquirrel->__sq_pushroottable; - g_pSquirrel->__sq_compilefile = g_pSquirrel->__sq_compilefile; g_pSquirrel->__sq_call = module.Offset(0x8650).As(); g_pSquirrel->__sq_call = g_pSquirrel->__sq_call; @@ -803,8 +733,6 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) MAKEHOOK(module.Offset(0x10190), &CallScriptInitCallbackHook, &CallScriptInitCallback); - MAKEHOOK(module.Offset(0xE3B0), &CSquirrelVM_initHook, &CSquirrelVM_init); - RegisterConCommand("script_client", ConCommand_script, "Executes script code on the client vm", FCVAR_CLIENTDLL); RegisterConCommand("script_ui", ConCommand_script, "Executes script code on the ui vm", FCVAR_CLIENTDLL); @@ -813,10 +741,6 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_getfunction = module.Offset(0x6CB0).As(); g_pSquirrel->__sq_getfunction = g_pSquirrel->__sq_getfunction; - - SquirrelFunctions s = {}; - g_pSquirrel->GenerateSquirrelFunctionsStruct(&s); - g_pPluginManager->InformSQVMLoad(ScriptContext::CLIENT, &s); } ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) @@ -828,7 +752,6 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_compilebuffer = module.Offset(0x3110).As(); g_pSquirrel->__sq_pushroottable = module.Offset(0x5840).As(); g_pSquirrel->__sq_call = module.Offset(0x8620).As(); - g_pSquirrel->__sq_compilefile = module.Offset(0x1CD80).As(); g_pSquirrel->__sq_newarray = module.Offset(0x39F0).As(); g_pSquirrel->__sq_arrayappend = module.Offset(0x3C70).As(); @@ -881,7 +804,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) MAKEHOOK(module.Offset(0x26E20), &DestroyVMHook, &DestroyVM); MAKEHOOK(module.Offset(0x799E0), &ScriptCompileErrorHook, &SQCompileError); MAKEHOOK(module.Offset(0x1D5C0), &CallScriptInitCallbackHook, &CallScriptInitCallback); - MAKEHOOK(module.Offset(0x17BE0), &CSquirrelVM_initHook, &CSquirrelVM_init); + // FCVAR_CHEAT and FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS allows clients to execute this, but since it's unsafe we only allow it when cheats // are enabled for script_client and script_ui, we don't use cheats, so clients can execute them on themselves all they want RegisterConCommand( @@ -891,10 +814,6 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) FCVAR_GAMEDLL | FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS | FCVAR_CHEAT); StubUnsafeSQFuncs(); - - SquirrelFunctions s = {}; - g_pSquirrel->GenerateSquirrelFunctionsStruct(&s); - g_pPluginManager->InformSQVMLoad(ScriptContext::SERVER, &s); } void InitialiseSquirrelManagers() diff --git a/NorthstarDLL/squirrel/squirrel.h b/NorthstarDLL/squirrel/squirrel.h index 9bf3a794..aa728fa5 100644 --- a/NorthstarDLL/squirrel/squirrel.h +++ b/NorthstarDLL/squirrel/squirrel.h @@ -3,7 +3,6 @@ #include "squirrelclasstypes.h" #include "squirrelautobind.h" #include "core/math/vector.h" -#include "plugins/plugin_abi.h" #include "mods/modmanager.h" // stolen from ttf2sdk: sqvm types @@ -38,8 +37,6 @@ const char* GetContextName_Short(ScriptContext context); eSQReturnType SQReturnTypeFromString(const char* pReturnType); const char* SQTypeNameFromID(const int iTypeId); -void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function); - ScriptContext ScriptContextFromString(std::string string); namespace NS::log @@ -47,6 +44,8 @@ namespace NS::log template std::shared_ptr squirrel_logger(); }; // namespace NS::log +void schedule_call_external(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function); + // This base class means that only the templated functions have to be rebuilt for each template instance // Cuts down on compile time by ~5 seconds class SquirrelManagerBase @@ -70,7 +69,6 @@ class SquirrelManagerBase sq_compilebufferType __sq_compilebuffer; sq_callType __sq_call; sq_raiseerrorType __sq_raiseerror; - sq_compilefileType __sq_compilefile; sq_newarrayType __sq_newarray; sq_arrayappendType __sq_arrayappend; @@ -131,11 +129,6 @@ class SquirrelManagerBase return __sq_raiseerror(sqvm, sError); } - inline bool compilefile(CSquirrelVM* sqvm, const char* path, const char* name, int a4) - { - return __sq_compilefile(sqvm, path, name, a4); - } - inline void newarray(HSquirrelVM* sqvm, const SQInteger stackpos = 0) { __sq_newarray(sqvm, stackpos); @@ -391,7 +384,6 @@ template class SquirrelManager : public virtual Squirrel SQRESULT setupfunc(const SQChar* funcname); void AddFuncOverride(std::string name, SQFunction func); void ProcessMessageBuffer(); - void GenerateSquirrelFunctionsStruct(SquirrelFunctions* s); }; template SquirrelManager* g_pSquirrel; diff --git a/NorthstarDLL/squirrel/squirrelclasstypes.h b/NorthstarDLL/squirrel/squirrelclasstypes.h index 67f69827..68b57bae 100644 --- a/NorthstarDLL/squirrel/squirrelclasstypes.h +++ b/NorthstarDLL/squirrel/squirrelclasstypes.h @@ -192,7 +192,6 @@ typedef SQRESULT (*sq_compilebufferType)( HSquirrelVM* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, SQBool bShouldThrowError); typedef SQRESULT (*sq_callType)(HSquirrelVM* sqvm, SQInteger iArgs, SQBool bShouldReturn, SQBool bThrowError); typedef SQInteger (*sq_raiseerrorType)(HSquirrelVM* sqvm, const SQChar* pError); -typedef bool (*sq_compilefileType)(CSquirrelVM* sqvm, const char* path, const char* name, int a4); // sq stack array funcs typedef void (*sq_newarrayType)(HSquirrelVM* sqvm, SQInteger iStackpos); diff --git a/NorthstarLauncher/main.cpp b/NorthstarLauncher/main.cpp index dd3b68f5..17128e5b 100644 --- a/NorthstarLauncher/main.cpp +++ b/NorthstarLauncher/main.cpp @@ -27,6 +27,8 @@ HMODULE hTier0Module; wchar_t exePath[4096]; wchar_t buffer[8192]; +bool noLoadPlugins = false; + DWORD GetProcessByName(std::wstring processName) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -290,6 +292,19 @@ bool LoadNorthstar() } ((bool (*)())Hook_Init)(); + FARPROC LoadPlugins = nullptr; + if (!noLoadPlugins) + { + LoadPlugins = GetProcAddress(hHookModule, "LoadPlugins"); + if (!hHookModule || LoadPlugins == nullptr) + { + std::cout << "Failed to get function pointer to LoadPlugins of Northstar.dll" << std::endl; + LibraryLoadError(GetLastError(), L"Northstar.dll", buffer); + return false; + } + ((bool (*)())LoadPlugins)(); + } + return true; } @@ -341,6 +356,8 @@ int main(int argc, char* argv[]) dedicated = true; else if (!strcmp(argv[i], "-nostubs")) nostubs = true; + else if (!strcmp(argv[i], "-noplugins")) + noLoadPlugins = true; if (!noOriginStartup && !dedicated) { -- cgit v1.2.3