aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDLL/plugins')
-rw-r--r--NorthstarDLL/plugins/plugin_abi.h151
-rw-r--r--NorthstarDLL/plugins/pluginbackend.cpp50
-rw-r--r--NorthstarDLL/plugins/pluginbackend.h40
-rw-r--r--NorthstarDLL/plugins/plugins.cpp340
-rw-r--r--NorthstarDLL/plugins/plugins.h59
5 files changed, 0 insertions, 640 deletions
diff --git a/NorthstarDLL/plugins/plugin_abi.h b/NorthstarDLL/plugins/plugin_abi.h
deleted file mode 100644
index 16b26a1c..00000000
--- a/NorthstarDLL/plugins/plugin_abi.h
+++ /dev/null
@@ -1,151 +0,0 @@
-#pragma once
-#include "squirrel/squirrelclasstypes.h"
-
-#define ABI_VERSION 3
-
-enum PluginLoadDLL
-{
- ENGINE = 0,
- CLIENT,
- SERVER
-};
-
-enum ObjectType
-{
- CONCOMMANDS = 0,
- CONVAR = 1,
-};
-
-struct SquirrelFunctions
-{
- RegisterSquirrelFuncType RegisterSquirrelFunc;
- sq_defconstType __sq_defconst;
-
- sq_compilebufferType __sq_compilebuffer;
- sq_callType __sq_call;
- sq_raiseerrorType __sq_raiseerror;
- sq_compilefileType __sq_compilefile;
-
- 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_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_getthisentityType __sq_getthisentity;
- sq_getobjectType __sq_getobject;
-
- sq_stackinfosType __sq_stackinfos;
-
- 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;
-
- sq_pushnewstructinstanceType __sq_pushnewstructinstance;
- sq_sealstructslotType __sq_sealstructslot;
-};
-
-struct MessageSource
-{
- const char* file;
- const char* func;
- int line;
-};
-
-// This is a modified version of spdlog::details::log_msg
-// This is so that we can make it cross DLL boundaries
-struct LogMsg
-{
- int level;
- uint64_t timestamp;
- const char* msg;
- MessageSource source;
- int pluginHandle;
-};
-
-extern "C"
-{
- typedef void (*loggerfunc_t)(LogMsg* msg);
- typedef void (*PLUGIN_RELAY_INVITE_TYPE)(const char* invite);
- typedef void* (*CreateObjectFunc)(ObjectType type);
-
- typedef void (*PluginFnCommandCallback_t)(void* command);
- typedef void (*PluginConCommandConstructorType)(
- void* newCommand, const char* name, PluginFnCommandCallback_t callback, const char* helpString, int flags, void* parent);
- typedef void (*PluginConVarRegisterType)(
- void* pConVar,
- const char* pszName,
- const char* pszDefaultValue,
- int nFlags,
- const char* pszHelpString,
- bool bMin,
- float fMin,
- bool bMax,
- float fMax,
- void* pCallback);
- typedef void (*PluginConVarMallocType)(void* pConVarMaloc, int a2, int a3);
-}
-
-struct PluginNorthstarData
-{
- const char* version;
- HMODULE northstarModule;
- int pluginHandle;
-};
-
-struct PluginInitFuncs
-{
- loggerfunc_t logger;
- PLUGIN_RELAY_INVITE_TYPE relayInviteFunc;
- CreateObjectFunc createObject;
-};
-
-struct PluginEngineData
-{
- PluginConCommandConstructorType ConCommandConstructor;
- PluginConVarMallocType conVarMalloc;
- PluginConVarRegisterType conVarRegister;
- void* ConVar_Vtable;
- void* IConVar_Vtable;
- void* g_pCVar;
-};
-
-/// <summary> 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.
-/// </summary>
-
-// 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);
-
-typedef void (*PLUGIN_INFORM_DLL_LOAD_TYPE)(const char* dll, PluginEngineData* data, void* dllPtr);
-typedef void (*PLUGIN_RUNFRAME)();
diff --git a/NorthstarDLL/plugins/pluginbackend.cpp b/NorthstarDLL/plugins/pluginbackend.cpp
deleted file mode 100644
index 850394ac..00000000
--- a/NorthstarDLL/plugins/pluginbackend.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#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"
-
-#include <filesystem>
-
-#define EXPORT extern "C" __declspec(dllexport)
-
-AUTOHOOK_INIT()
-
-PluginCommunicationHandler* g_pPluginCommunicationhandler;
-
-static PluginDataRequest storedRequest {PluginDataRequestType::END, (PluginRespondDataCallable) nullptr};
-
-void PluginCommunicationHandler::RunFrame()
-{
- std::lock_guard<std::mutex> lock(requestMutex);
- if (!requestQueue.empty())
- {
- storedRequest = requestQueue.front();
- switch (storedRequest.type)
- {
- default:
- spdlog::error("{} was called with invalid request type '{}'", __FUNCTION__, static_cast<int>(storedRequest.type));
- }
- requestQueue.pop();
- }
-}
-
-void PluginCommunicationHandler::PushRequest(PluginDataRequestType type, PluginRespondDataCallable func)
-{
- std::lock_guard<std::mutex> lock(requestMutex);
- requestQueue.push(PluginDataRequest {type, func});
-}
-
-void InformPluginsDLLLoad(fs::path dllPath, void* address)
-{
- std::string dllName = dllPath.filename().string();
-
- void* data = NULL;
- if (strncmp(dllName.c_str(), "engine.dll", 10) == 0)
- data = &g_pPluginCommunicationhandler->m_sEngineData;
-
- g_pPluginManager->InformDLLLoad(dllName.c_str(), data, address);
-}
diff --git a/NorthstarDLL/plugins/pluginbackend.h b/NorthstarDLL/plugins/pluginbackend.h
deleted file mode 100644
index 45cd42f3..00000000
--- a/NorthstarDLL/plugins/pluginbackend.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-#include "plugin_abi.h"
-
-#include <queue>
-#include <mutex>
-
-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);
-
-public:
- std::queue<PluginDataRequest> requestQueue = {};
- std::mutex requestMutex;
-
- PluginEngineData m_sEngineData {};
-};
-
-void InformPluginsDLLLoad(fs::path dllPath, void* address);
-extern PluginCommunicationHandler* g_pPluginCommunicationhandler;
diff --git a/NorthstarDLL/plugins/plugins.cpp b/NorthstarDLL/plugins/plugins.cpp
deleted file mode 100644
index 72b64566..00000000
--- a/NorthstarDLL/plugins/plugins.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-#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 <optional>
-#include <regex>
-
-#include "util/version.h"
-#include "pluginbackend.h"
-#include "util/wininfo.h"
-#include "logging/logging.h"
-#include "dedicated/dedicated.h"
-
-PluginManager* g_pPluginManager;
-
-void freeLibrary(HMODULE hLib)
-{
- if (!FreeLibrary(hLib))
- {
- spdlog::error("There was an error while trying to free library");
- }
-}
-
-EXPORT void PLUGIN_LOG(LogMsg* msg)
-{
- 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);
-}
-
-EXPORT void* CreateObject(ObjectType type)
-{
- switch (type)
- {
- case ObjectType::CONVAR:
- return (void*)new ConVar;
- case ObjectType::CONCOMMANDS:
- return (void*)new ConCommand;
- default:
- return NULL;
- }
-}
-
-std::optional<Plugin> PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* funcs, PluginNorthstarData* data)
-{
-
- Plugin plugin {};
-
- std::string pathstring = path.string();
- std::wstring wpath = 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)
- {
- NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError()));
- return std::nullopt;
- }
- HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(IDR_RCDATA1), RT_RCDATA);
-
- 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);
-
- rapidjson_document manifestJSON;
- manifestJSON.Parse(manifest.c_str());
-
- 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()))
- {
- NS::log::PLUGINSYS->error(
- "'{}' has an incompatible API version number in its manifest. Current ABI version is '{}'", pathstring, ABI_VERSION);
- return std::nullopt;
- }
- // Passed all checks, going to actually load it now
-
- HMODULE pluginLib =
- LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); // Load the DLL with lib folders
- 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)
- {
- NS::log::PLUGINSYS->info("Library '{}' has no function 'PLUGIN_INIT'", pathstring);
- return std::nullopt;
- }
- 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();
-
- 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
- {
- plugin.dependencyName = plugin.name;
- }
-
- if (std::find_if(
- plugin.dependencyName.begin(),
- plugin.dependencyName.end(),
- [&](char c) -> bool { return !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'); }) !=
- plugin.dependencyName.end())
- {
- NS::log::PLUGINSYS->warn("Dependency string \"{}\" in {} is not valid a squirrel constant!", plugin.dependencyName, plugin.name);
- }
-
- 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.inform_dll_load = (PLUGIN_INFORM_DLL_LOAD_TYPE)GetProcAddress(pluginLib, "PLUGIN_INFORM_DLL_LOAD");
-
- plugin.run_frame = (PLUGIN_RUNFRAME)GetProcAddress(pluginLib, "PLUGIN_RUNFRAME");
-
- plugin.handle = m_vLoadedPlugins.size();
- plugin.logger = std::make_shared<ColoredLogger>(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;
-}
-
-inline void FindPlugins(fs::path pluginPath, std::vector<fs::path>& paths)
-{
- // ensure dirs exist
- if (!fs::exists(pluginPath) || !fs::is_directory(pluginPath))
- {
- return;
- }
-
- for (const fs::directory_entry& entry : fs::directory_iterator(pluginPath))
- {
- if (fs::is_regular_file(entry) && entry.path().extension() == ".dll")
- paths.emplace_back(entry.path());
- }
-}
-
-bool PluginManager::LoadPlugins()
-{
- if (strstr(GetCommandLineA(), "-noplugins") != NULL)
- {
- NS::log::PLUGINSYS->warn("-noplugins detected; skipping loading plugins");
- return false;
- }
-
- fs::create_directories(GetThunderstoreModFolderPath());
-
- std::vector<fs::path> paths;
-
- pluginPath = GetNorthstarPrefix() + "\\plugins";
-
- PluginNorthstarData data {};
- std::string ns_version {version};
-
- PluginInitFuncs funcs {};
- funcs.logger = PLUGIN_LOG;
- funcs.relayInviteFunc = nullptr;
- funcs.createObject = CreateObject;
-
- data.version = ns_version.c_str();
- data.northstarModule = g_NorthstarModule;
-
- fs::path libPath = fs::absolute(pluginPath + "\\lib");
- if (fs::exists(libPath) && fs::is_directory(libPath))
- AddDllDirectory(libPath.wstring().c_str());
-
- FindPlugins(pluginPath, paths);
-
- // Special case for Thunderstore mods dir
- std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
- // Set up regex for `AUTHOR-MOD-VERSION` pattern
- std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
- for (fs::directory_entry dir : thunderstoreModsDir)
- {
- fs::path pluginsDir = dir.path() / "plugins";
- // Use regex to match `AUTHOR-MOD-VERSION` pattern
- if (!std::regex_match(dir.path().string(), pattern))
- {
- spdlog::warn("The following directory did not match 'AUTHOR-MOD-VERSION': {}", dir.path().string());
- continue; // skip loading package that doesn't match
- }
-
- fs::path libDir = fs::absolute(pluginsDir / "lib");
- if (fs::exists(libDir) && fs::is_directory(libDir))
- AddDllDirectory(libDir.wstring().c_str());
-
- FindPlugins(pluginsDir, paths);
- }
-
- if (paths.empty())
- {
- NS::log::PLUGINSYS->warn("Could not find any plugins. Skipped loading plugins");
- return false;
- }
-
- for (fs::path path : paths)
- {
- if (LoadPlugin(path, &funcs, &data))
- data.pluginHandle += 1;
- }
- return true;
-}
-
-void PluginManager::InformSQVMLoad(ScriptContext context, SquirrelFunctions* s)
-{
- for (auto plugin : m_vLoadedPlugins)
- {
- 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);
- }
- }
-}
-
-void PluginManager::InformSQVMCreated(ScriptContext context, CSquirrelVM* sqvm)
-{
- for (auto plugin : m_vLoadedPlugins)
- {
- if (plugin.inform_sqvm_created != NULL)
- {
- plugin.inform_sqvm_created(context, sqvm);
- }
- }
-}
-
-void PluginManager::InformSQVMDestroyed(ScriptContext context)
-{
- for (auto plugin : m_vLoadedPlugins)
- {
- if (plugin.inform_sqvm_destroyed != NULL)
- {
- plugin.inform_sqvm_destroyed(context);
- }
- }
-}
-
-void PluginManager::InformDLLLoad(const char* dll, void* data, void* dllPtr)
-{
- for (auto plugin : m_vLoadedPlugins)
- {
- if (plugin.inform_dll_load != NULL)
- {
- plugin.inform_dll_load(dll, (PluginEngineData*)data, dllPtr);
- }
- }
-}
-
-void PluginManager::RunFrame()
-{
- for (auto plugin : m_vLoadedPlugins)
- {
- if (plugin.run_frame != NULL)
- {
- plugin.run_frame();
- }
- }
-}
diff --git a/NorthstarDLL/plugins/plugins.h b/NorthstarDLL/plugins/plugins.h
deleted file mode 100644
index 4e841f27..00000000
--- a/NorthstarDLL/plugins/plugins.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-#include "plugin_abi.h"
-
-const int IDR_RCDATA1 = 101;
-
-class Plugin
-{
-public:
- std::string name;
- std::string displayName;
- std::string dependencyName;
- std::string description;
-
- std::string api_version;
- std::string version;
-
- // 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<ColoredLogger> 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_INFORM_DLL_LOAD_TYPE inform_dll_load;
-
- PLUGIN_RUNFRAME run_frame;
-};
-
-class PluginManager
-{
-public:
- std::vector<Plugin> m_vLoadedPlugins;
-
-public:
- bool LoadPlugins();
- std::optional<Plugin> 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 InformDLLLoad(const char* dll, void* data, void* dllPtr);
-
- void RunFrame();
-
-private:
- std::string pluginPath;
-};
-
-extern PluginManager* g_pPluginManager;