309 lines
10 KiB
C++
309 lines
10 KiB
C++
#include "pch.h"
|
|
#include "hooks.h"
|
|
#include "main.h"
|
|
#include "squirrel.h"
|
|
#include "dedicated.h"
|
|
#include "dedicatedmaterialsystem.h"
|
|
#include "sourceconsole.h"
|
|
#include "logging.h"
|
|
#include "concommand.h"
|
|
#include "modmanager.h"
|
|
#include "filesystem.h"
|
|
#include "serverauthentication.h"
|
|
#include "scriptmodmenu.h"
|
|
#include "scriptserverbrowser.h"
|
|
#include "keyvalues.h"
|
|
#include "masterserver.h"
|
|
#include "gameutils.h"
|
|
#include "chatcommand.h"
|
|
#include "modlocalisation.h"
|
|
#include "playlist.h"
|
|
#include "miscserverscript.h"
|
|
#include "clientauthhooks.h"
|
|
#include "latencyflex.h"
|
|
#include "scriptbrowserhooks.h"
|
|
#include "scriptmainmenupromos.h"
|
|
#include "miscclientfixes.h"
|
|
#include "miscserverfixes.h"
|
|
#include "rpakfilesystem.h"
|
|
#include "bansystem.h"
|
|
#include "memalloc.h"
|
|
#include "maxplayers.h"
|
|
#include "languagehooks.h"
|
|
#include "audio.h"
|
|
#include "buildainfile.h"
|
|
#include "configurables.h"
|
|
#include "serverchathooks.h"
|
|
#include "clientchathooks.h"
|
|
#include "localchatwriter.h"
|
|
#include "scriptservertoclientstringcommand.h"
|
|
#include "plugin_abi.h"
|
|
#include "plugins.h"
|
|
#include "debugoverlay.h"
|
|
#include "clientvideooverrides.h"
|
|
#include "clientruihooks.h"
|
|
#include <string.h>
|
|
#include "version.h"
|
|
#include "pch.h"
|
|
#include "scriptutility.h"
|
|
|
|
#include "rapidjson/document.h"
|
|
#include "rapidjson/stringbuffer.h"
|
|
#include "rapidjson/writer.h"
|
|
#include "rapidjson/error/en.h"
|
|
#include "ExploitFixes.h"
|
|
#include "scriptjson.h"
|
|
|
|
typedef void (*initPluginFuncPtr)(void* (*getPluginObject)(PluginObject));
|
|
|
|
bool initialised = false;
|
|
|
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
|
{
|
|
switch (ul_reason_for_call)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void WaitForDebugger(HMODULE baseAddress)
|
|
{
|
|
// earlier waitfordebugger call than is in vanilla, just so we can debug stuff a little easier
|
|
if (CommandLine()->CheckParm("-waitfordebugger"))
|
|
{
|
|
spdlog::info("waiting for debugger...");
|
|
|
|
while (!IsDebuggerPresent())
|
|
Sleep(100);
|
|
}
|
|
}
|
|
|
|
void freeLibrary(HMODULE hLib)
|
|
{
|
|
if (!FreeLibrary(hLib))
|
|
{
|
|
spdlog::error("There was an error while trying to free library");
|
|
}
|
|
}
|
|
|
|
bool LoadPlugins()
|
|
{
|
|
|
|
std::vector<fs::path> 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()
|
|
{
|
|
if (initialised)
|
|
{
|
|
// spdlog::warn("Called InitialiseNorthstar more than once!"); // it's actually 100% fine for that to happen
|
|
return false;
|
|
}
|
|
|
|
initialised = true;
|
|
|
|
parseConfigurables();
|
|
InitialiseVersion();
|
|
|
|
// Fix some users' failure to connect to respawn datacenters
|
|
SetEnvironmentVariableA("OPENSSL_ia32cap", "~0x200000200000000");
|
|
|
|
curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base);
|
|
|
|
InitialiseLogging();
|
|
InstallInitialHooks();
|
|
CreateLogFiles();
|
|
|
|
// Write launcher version to log
|
|
spdlog::info("NorthstarLauncher version: {}", version);
|
|
|
|
InitialiseInterfaceCreationHooks();
|
|
|
|
AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions);
|
|
AddDllLoadCallback("engine.dll", WaitForDebugger);
|
|
AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions);
|
|
AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions);
|
|
|
|
// dedi patches
|
|
{
|
|
AddDllLoadCallbackForDedicatedServer("tier0.dll", InitialiseDedicatedOrigin);
|
|
AddDllLoadCallbackForDedicatedServer("engine.dll", InitialiseDedicated);
|
|
AddDllLoadCallbackForDedicatedServer("server.dll", InitialiseDedicatedServerGameDLL);
|
|
AddDllLoadCallbackForDedicatedServer("materialsystem_dx11.dll", InitialiseDedicatedMaterialSystem);
|
|
// this fucking sucks, but seemingly we somehow load after rtech_game???? unsure how, but because of this we have to apply patches
|
|
// here, not on rtech_game load
|
|
AddDllLoadCallbackForDedicatedServer("engine.dll", InitialiseDedicatedRtechGame);
|
|
}
|
|
|
|
AddDllLoadCallback("engine.dll", InitialiseConVars);
|
|
AddDllLoadCallback("engine.dll", InitialiseConCommands);
|
|
|
|
// client-exclusive patches
|
|
{
|
|
|
|
AddDllLoadCallbackForClient("tier0.dll", InitialiseTier0LanguageHooks);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrel);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseSourceConsole);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseChatCommands);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseScriptModMenu);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseScriptServerBrowser);
|
|
AddDllLoadCallbackForClient("localize.dll", InitialiseModLocalisation);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseClientAuthHooks);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseLatencyFleX);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseScriptExternalBrowserHooks);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseScriptMainMenuPromos);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseMiscClientFixes);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseClientPrintHooks);
|
|
AddDllLoadCallbackForClient("client.dll", InitialisePluginCommands);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseClientChatHooks);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseLocalChatWriter);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseScriptServerToClientStringCommands);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseEngineClientVideoOverrides);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseEngineClientRUIHooks);
|
|
AddDllLoadCallbackForClient("engine.dll", InitialiseDebugOverlay);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrelJson);
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrelUtilityFunctions);
|
|
// audio hooks
|
|
AddDllLoadCallbackForClient("client.dll", InitialiseMilesAudioHooks);
|
|
}
|
|
|
|
AddDllLoadCallback("engine.dll", InitialiseEngineSpewFuncHooks);
|
|
AddDllLoadCallback("server.dll", InitialiseServerSquirrel);
|
|
AddDllLoadCallback("engine.dll", InitialiseBanSystem);
|
|
AddDllLoadCallback("engine.dll", InitialiseServerAuthentication);
|
|
AddDllLoadCallback("engine.dll", InitialiseSharedMasterServer);
|
|
AddDllLoadCallback("server.dll", InitialiseMiscServerScriptCommand);
|
|
AddDllLoadCallback("server.dll", InitialiseMiscServerFixes);
|
|
AddDllLoadCallback("server.dll", InitialiseBuildAINFileHooks);
|
|
AddDllLoadCallback("server.dll", InitialiseServerSquirrelUtilityFunctions);
|
|
AddDllLoadCallback("server.dll", InitialiseServerSquirrelJson);
|
|
|
|
AddDllLoadCallback("engine.dll", InitialisePlaylistHooks);
|
|
|
|
AddDllLoadCallback("filesystem_stdio.dll", InitialiseFilesystem);
|
|
AddDllLoadCallback("engine.dll", InitialiseEngineRpakFilesystem);
|
|
AddDllLoadCallback("engine.dll", InitialiseKeyValues);
|
|
|
|
AddDllLoadCallback("engine.dll", InitialiseServerChatHooks_Engine);
|
|
AddDllLoadCallback("server.dll", InitialiseServerChatHooks_Server);
|
|
|
|
// maxplayers increase
|
|
AddDllLoadCallback("engine.dll", InitialiseMaxPlayersOverride_Engine);
|
|
AddDllLoadCallback("client.dll", InitialiseMaxPlayersOverride_Client);
|
|
AddDllLoadCallback("server.dll", InitialiseMaxPlayersOverride_Server);
|
|
|
|
// mod manager after everything else
|
|
AddDllLoadCallback("engine.dll", InitialiseModManager);
|
|
|
|
{
|
|
// 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();
|
|
|
|
return true;
|
|
}
|