diff --git a/CMakeLists.txt b/CMakeLists.txt index a9646ae10..c9516e521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,3 +50,7 @@ include_directories(primedev/thirdparty) # Targets add_subdirectory(primedev) +# Forces Minizip to not use functions that are not available in Win 7 libraries. +if(WIN32) + target_compile_definitions(minizip PUBLIC -D_WIN32_WINNT=0x0601) +endif() diff --git a/primedev/Northstar.cmake b/primedev/Northstar.cmake index 4e8ec973b..35383e69c 100644 --- a/primedev/Northstar.cmake +++ b/primedev/Northstar.cmake @@ -52,7 +52,6 @@ add_library( "core/memalloc.cpp" "core/memalloc.h" "core/sourceinterface.cpp" - "core/sourceinterface.h" "core/tier0.cpp" "core/tier0.h" "core/tier1.cpp" diff --git a/primedev/core/convar/convar.h b/primedev/core/convar/convar.h index f0366b466..33a50c1c4 100644 --- a/primedev/core/convar/convar.h +++ b/primedev/core/convar/convar.h @@ -1,5 +1,4 @@ #pragma once -#include "core/sourceinterface.h" #include "core/math/color.h" #include "cvar.h" #include "concommand.h" diff --git a/primedev/core/filesystem/rpakfilesystem.cpp b/primedev/core/filesystem/rpakfilesystem.cpp index ebb9085a7..c3e5e74ee 100644 --- a/primedev/core/filesystem/rpakfilesystem.cpp +++ b/primedev/core/filesystem/rpakfilesystem.cpp @@ -342,7 +342,7 @@ void PakLoadManager::UnloadDependentPaks(PakHandle handle) static void HandlePakAliases(std::string& originalPath) { // convert the pak being loaded to its aliased one, e.g. aliasing mp_hub_timeshift => sp_hub_timeshift - for (int64_t i = g_pModManager->m_LoadedMods.size() - 1; i > PakHandle::INVALID; i--) + for (int64_t i = g_pModManager->m_LoadedMods.size() - 1; i > -1; i--) { Mod* mod = &g_pModManager->m_LoadedMods[i]; if (!mod->m_bEnabled) @@ -350,7 +350,7 @@ static void HandlePakAliases(std::string& originalPath) if (mod->RpakAliases.find(originalPath) != mod->RpakAliases.end()) { - originalPath = (mod->m_ModDirectory / "paks" / mod->RpakAliases[originalPath]).string(); + originalPath = mod->RpakAliases[originalPath]; return; } } diff --git a/primedev/core/sourceinterface.cpp b/primedev/core/sourceinterface.cpp index 74e4a9963..7ce339255 100644 --- a/primedev/core/sourceinterface.cpp +++ b/primedev/core/sourceinterface.cpp @@ -1,4 +1,3 @@ -#include "sourceinterface.h" #include "logging/sourceconsole.h" // really wanted to do a modular callback system here but honestly couldn't be bothered so hardcoding stuff for now: todo later diff --git a/primedev/core/sourceinterface.h b/primedev/core/sourceinterface.h deleted file mode 100644 index 730339daa..000000000 --- a/primedev/core/sourceinterface.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include - -// interface return status -enum class InterfaceStatus : int -{ - IFACE_OK = 0, - IFACE_FAILED, -}; - -// literally just copied from ttf2sdk definition -typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); - -template class SourceInterface -{ -private: - T* m_interface; - -public: - SourceInterface(const std::string& moduleName, const std::string& interfaceName) - { - HMODULE handle = GetModuleHandleA(moduleName.c_str()); - CreateInterfaceFn createInterface = (CreateInterfaceFn)GetProcAddress(handle, "CreateInterface"); - m_interface = (T*)createInterface(interfaceName.c_str(), NULL); - if (m_interface == nullptr) - spdlog::error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName); - } - - T* operator->() const { return m_interface; } - - operator T*() const { return m_interface; } -}; diff --git a/primedev/core/tier1.h b/primedev/core/tier1.h index d162e7c84..36f577cc2 100644 --- a/primedev/core/tier1.h +++ b/primedev/core/tier1.h @@ -7,6 +7,12 @@ #define CREATEINTERFACE_PROCNAME "CreateInterface" +enum class InterfaceStatus : int +{ + IFACE_OK = 0, + IFACE_FAILED, +}; + typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); CMemory Sys_GetFactoryPtr(const std::string& svModuleName, const std::string& svFact); diff --git a/primedev/logging/sourceconsole.h b/primedev/logging/sourceconsole.h index 35cc1723c..8c647fb42 100644 --- a/primedev/logging/sourceconsole.h +++ b/primedev/logging/sourceconsole.h @@ -1,5 +1,4 @@ #pragma once -#include "core/sourceinterface.h" #include "spdlog/sinks/base_sink.h" #include diff --git a/primedev/mods/compiled/modkeyvalues.cpp b/primedev/mods/compiled/modkeyvalues.cpp index e44a81d31..dfff706d0 100644 --- a/primedev/mods/compiled/modkeyvalues.cpp +++ b/primedev/mods/compiled/modkeyvalues.cpp @@ -3,8 +3,6 @@ #include -AUTOHOOK_INIT() - void ModManager::TryBuildKeyValues(const char* filename) { spdlog::info("Building KeyValues for file {}", filename); diff --git a/primedev/plugins/interfaces/IPluginId.h b/primedev/plugins/interfaces/IPluginId.h index dc4c548b3..0b025224b 100644 --- a/primedev/plugins/interfaces/IPluginId.h +++ b/primedev/plugins/interfaces/IPluginId.h @@ -18,6 +18,7 @@ enum class PluginString : int enum class PluginField : int { CONTEXT = 0, + COLOR = 1, }; // an interface that is required from every plugin to query data about it diff --git a/primedev/plugins/interfaces/interface.cpp b/primedev/plugins/interfaces/interface.cpp index bc9005421..e82005604 100644 --- a/primedev/plugins/interfaces/interface.cpp +++ b/primedev/plugins/interfaces/interface.cpp @@ -1,4 +1,5 @@ #include +#include "core/tier1.h" #include "interface.h" InterfaceReg* s_pInterfaceRegs; diff --git a/primedev/plugins/interfaces/sys/ISys.cpp b/primedev/plugins/interfaces/sys/ISys.cpp index 6b0b41ddf..948e7d90b 100644 --- a/primedev/plugins/interfaces/sys/ISys.cpp +++ b/primedev/plugins/interfaces/sys/ISys.cpp @@ -1,3 +1,4 @@ +#include "core/tier1.h" #include "plugins/interfaces/interface.h" #include "ISys.h" #include "plugins/plugins.h" diff --git a/primedev/plugins/plugins.cpp b/primedev/plugins/plugins.cpp index 92be9d5cf..3e6231676 100644 --- a/primedev/plugins/plugins.cpp +++ b/primedev/plugins/plugins.cpp @@ -2,7 +2,6 @@ #include "pluginmanager.h" #include "squirrel/squirrel.h" #include "util/wininfo.h" -#include "core/sourceinterface.h" #include "logging/logging.h" #include "dedicated/dedicated.h" @@ -24,6 +23,7 @@ bool isValidSquirrelIdentifier(std::string s) Plugin::Plugin(std::string path) : m_location(path) + , m_logColor(NS::Colors::PLUGIN) { HMODULE pluginModule = GetModuleHandleA(path.c_str()); @@ -70,6 +70,13 @@ Plugin::Plugin(std::string path) m_runOnServer = context & PluginContext::DEDICATED; m_runOnClient = context & PluginContext::CLIENT; + int64_t logColor = m_pluginId->GetField(PluginField::COLOR); + // Apply custom colour if plugin has specified one + if ((logColor & 0xFFFFFF) != 0) + { + m_logColor = Color((int)(logColor & 0xFF), (int)((logColor >> 8) & 0xFF), (int)((logColor >> 16) & 0xFF)); + } + if (!name) { NS::log::PLUGINSYS->error("Could not load name of plugin at '{}'", path); @@ -106,7 +113,7 @@ Plugin::Plugin(std::string path) return; } - m_logger = std::make_shared(m_logName, NS::Colors::PLUGIN); + m_logger = std::make_shared(m_logName, m_logColor); RegisterLogger(m_logger); if (IsDedicatedServer() && !m_runOnServer) diff --git a/primedev/plugins/plugins.h b/primedev/plugins/plugins.h index d004038c4..95ec08b5c 100644 --- a/primedev/plugins/plugins.h +++ b/primedev/plugins/plugins.h @@ -1,5 +1,5 @@ #pragma once -#include "core/sourceinterface.h" +#include "core/tier1.h" #include "plugins/interfaces/interface.h" #include "plugins/interfaces/IPluginId.h" #include "plugins/interfaces/IPluginCallbacks.h" @@ -20,6 +20,7 @@ class Plugin std::string m_location; // path of the dll bool m_runOnServer; bool m_runOnClient; + Color m_logColor; public: HMODULE m_handle; diff --git a/primedev/scripts/client/clientchathooks.cpp b/primedev/scripts/client/clientchathooks.cpp index e084f47e9..c0a06dd2c 100644 --- a/primedev/scripts/client/clientchathooks.cpp +++ b/primedev/scripts/client/clientchathooks.cpp @@ -6,12 +6,8 @@ #include -AUTOHOOK_INIT() - -// clang-format off -AUTOHOOK(CHudChat__AddGameLine, client.dll + 0x22E580, -void, __fastcall, (void* self, const char* message, int inboxId, bool isTeam, bool isDead)) -// clang-format on +static void(__fastcall* o_pCHudChat__AddGameLine)(void* self, const char* message, int inboxId, bool isTeam, bool isDead) = nullptr; +static void __fastcall h_CHudChat__AddGameLine(void* self, const char* message, int inboxId, bool isTeam, bool isDead) { // This hook is called for each HUD, but we only want our logic to run once. if (self != *CHudChat::allHuds) @@ -36,7 +32,7 @@ void, __fastcall, (void* self, const char* message, int inboxId, bool isTeam, bo "CHudChat_ProcessMessageStartThread", static_cast(senderId) - 1, payload, isTeam, isDead, type); if (result == SQRESULT_ERROR) for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - CHudChat__AddGameLine(hud, message, inboxId, isTeam, isDead); + o_pCHudChat__AddGameLine(hud, message, inboxId, isTeam, isDead); } ADD_SQFUNC("void", NSChatWrite, "int context, string text", "", ScriptContext::CLIENT) @@ -68,5 +64,6 @@ ADD_SQFUNC("void", NSChatWriteLine, "int context, string text", "", ScriptContex ON_DLL_LOAD_CLIENT("client.dll", ClientChatHooks, (CModule module)) { - AUTOHOOK_DISPATCH() + o_pCHudChat__AddGameLine = module.Offset(0x22E580).RCast(); + HookAttach(&(PVOID&)o_pCHudChat__AddGameLine, (PVOID)h_CHudChat__AddGameLine); } diff --git a/primedev/server/auth/serverauthentication.cpp b/primedev/server/auth/serverauthentication.cpp index d0d4c698f..58268bcfa 100644 --- a/primedev/server/auth/serverauthentication.cpp +++ b/primedev/server/auth/serverauthentication.cpp @@ -19,8 +19,6 @@ #include #include -AUTOHOOK_INIT() - // global vars ServerAuthenticationManager* g_pServerAuthentication; CBaseServer__RejectConnectionType CBaseServer__RejectConnection; @@ -207,9 +205,25 @@ void ServerAuthenticationManager::WritePersistentData(CBaseClient* pPlayer) char* pNextPlayerToken; uint64_t iNextPlayerUid; -// clang-format off -AUTOHOOK(CBaseServer__ConnectClient, engine.dll + 0x114430, -void*,, ( +static void* (*o_pCBaseServer__ConnectClient)( + void* self, + void* addr, + void* a3, + uint32_t a4, + uint32_t a5, + int32_t a6, + void* a7, + char* playerName, + char* serverFilter, + void* a10, + char a11, + void* a12, + char a13, + char a14, + int64_t uid, + uint32_t a16, + uint32_t a17) = nullptr; +static void* h_CBaseServer__ConnectClient( void* self, void* addr, void* a3, @@ -226,22 +240,21 @@ void*,, ( char a14, int64_t uid, uint32_t a16, - uint32_t a17)) -// clang-format on + uint32_t a17) { // auth tokens are sent with serverfilter, can't be accessed from player struct to my knowledge, so have to do this here pNextPlayerToken = serverFilter; iNextPlayerUid = uid; - return CBaseServer__ConnectClient(self, addr, a3, a4, a5, a6, a7, playerName, serverFilter, a10, a11, a12, a13, a14, uid, a16, a17); + return o_pCBaseServer__ConnectClient(self, addr, a3, a4, a5, a6, a7, playerName, serverFilter, a10, a11, a12, a13, a14, uid, a16, a17); } ConVar* Cvar_ns_allowuserclantags; -// clang-format off -AUTOHOOK(CBaseClient__Connect, engine.dll + 0x101740, -bool,, (CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, void* a5, char pDisconnectReason[256], void* a7)) -// clang-format on +static bool (*o_pCBaseClient__Connect)( + CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, void* a5, char pDisconnectReason[256], void* a7) = nullptr; +static bool +h_CBaseClient__Connect(CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, void* a5, char pDisconnectReason[256], void* a7) { const char* pAuthenticationFailure = nullptr; char pVerifiedName[64]; @@ -267,7 +280,7 @@ bool,, (CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, voi } // try to actually connect the player - if (!CBaseClient__Connect(self, pVerifiedName, pNetChannel, bFakePlayer, a5, pDisconnectReason, a7)) + if (!o_pCBaseClient__Connect(self, pVerifiedName, pNetChannel, bFakePlayer, a5, pDisconnectReason, a7)) return false; // we already know this player's authentication data is legit, actually write it to them now @@ -279,10 +292,8 @@ bool,, (CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, voi return true; } -// clang-format off -AUTOHOOK(CBaseClient__ActivatePlayer, engine.dll + 0x100F80, -void,, (CBaseClient* self)) -// clang-format on +static void (*o_pCBaseClient__ActivatePlayer)(CBaseClient* self) = nullptr; +static void h_CBaseClient__ActivatePlayer(CBaseClient* self) { // if we're authed, write our persistent data // RemovePlayerAuthData returns true if it removed successfully, i.e. on first call only, and we only want to write on >= second call @@ -294,13 +305,11 @@ void,, (CBaseClient* self)) g_pServerPresence->SetPlayerCount((int)g_pServerAuthentication->m_PlayerAuthenticationData.size()); } - CBaseClient__ActivatePlayer(self); + o_pCBaseClient__ActivatePlayer(self); } -// clang-format off -AUTOHOOK(_CBaseClient__Disconnect, engine.dll + 0x1012C0, -void,, (CBaseClient* self, uint32_t unknownButAlways1, const char* pReason, ...)) -// clang-format on +static void (*o_pCBaseClient__Disconnect)(CBaseClient* self, uint32_t unknownButAlways1, const char* pReason, ...) = nullptr; +static void h_CBaseClient__Disconnect(CBaseClient* self, uint32_t unknownButAlways1, const char* pReason, ...) { // have to manually format message because can't pass varargs to original func char buf[1024]; @@ -328,7 +337,7 @@ void,, (CBaseClient* self, uint32_t unknownButAlways1, const char* pReason, ...) g_pServerPresence->SetPlayerCount((int)g_pServerAuthentication->m_PlayerAuthenticationData.size()); - _CBaseClient__Disconnect(self, unknownButAlways1, buf); + o_pCBaseClient__Disconnect(self, unknownButAlways1, buf); } void ConCommand_ns_resetpersistence(const CCommand& args) @@ -346,7 +355,17 @@ void ConCommand_ns_resetpersistence(const CCommand& args) ON_DLL_LOAD_RELIESON("engine.dll", ServerAuthentication, (ConCommand, ConVar), (CModule module)) { - AUTOHOOK_DISPATCH() + o_pCBaseServer__ConnectClient = module.Offset(0x114430).RCast(); + HookAttach(&(PVOID&)o_pCBaseServer__ConnectClient, (PVOID)h_CBaseServer__ConnectClient); + + o_pCBaseClient__Connect = module.Offset(0x101740).RCast(); + HookAttach(&(PVOID&)o_pCBaseClient__Connect, (PVOID)h_CBaseClient__Connect); + + o_pCBaseClient__ActivatePlayer = module.Offset(0x100F80).RCast(); + HookAttach(&(PVOID&)o_pCBaseClient__ActivatePlayer, (PVOID)h_CBaseClient__ActivatePlayer); + + o_pCBaseClient__Disconnect = module.Offset(0x1012C0).RCast(); + HookAttach(&(PVOID&)o_pCBaseClient__Disconnect, (PVOID)h_CBaseClient__Disconnect); g_pServerAuthentication = new ServerAuthenticationManager; diff --git a/primedev/server/buildainfile.cpp b/primedev/server/buildainfile.cpp index 19a6d0e36..456c84f07 100644 --- a/primedev/server/buildainfile.cpp +++ b/primedev/server/buildainfile.cpp @@ -7,8 +7,6 @@ namespace fs = std::filesystem; -AUTOHOOK_INIT() - const int AINET_VERSION_NUMBER = 57; const int AINET_SCRIPT_VERSION_NUMBER = 21; const int PLACEHOLDER_CRC = 0; @@ -359,22 +357,18 @@ void DumpAINInfo(CAI_Network* aiNetwork) writeStream.close(); } -// clang-format off -AUTOHOOK(CAI_NetworkBuilder__Build, server.dll + 0x385E20, -void, __fastcall, (void* builder, CAI_Network* aiNetwork, void* unknown)) -// clang-format on +static void(__fastcall* o_pCAI_NetworkBuilder__Build)(void* builder, CAI_Network* aiNetwork, void* unknown) = nullptr; +static void __fastcall h_CAI_NetworkBuilder__Build(void* builder, CAI_Network* aiNetwork, void* unknown) { - CAI_NetworkBuilder__Build(builder, aiNetwork, unknown); + o_pCAI_NetworkBuilder__Build(builder, aiNetwork, unknown); DumpAINInfo(aiNetwork); } -// clang-format off -AUTOHOOK(LoadAINFile, server.dll + 0x3933A0, -void, __fastcall, (void* aimanager, void* buf, const char* filename)) -// clang-format on +static void(__fastcall* o_pLoadAINFile)(void* aimanager, void* buf, const char* filename) = nullptr; +static void __fastcall h_LoadAINFile(void* aimanager, void* buf, const char* filename) { - LoadAINFile(aimanager, buf, filename); + o_pLoadAINFile(aimanager, buf, filename); if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) { @@ -385,7 +379,11 @@ void, __fastcall, (void* aimanager, void* buf, const char* filename)) ON_DLL_LOAD("server.dll", BuildAINFile, (CModule module)) { - AUTOHOOK_DISPATCH() + o_pCAI_NetworkBuilder__Build = module.Offset(0x385E20).RCast(); + HookAttach(&(PVOID&)o_pCAI_NetworkBuilder__Build, (PVOID)h_CAI_NetworkBuilder__Build); + + o_pLoadAINFile = module.Offset(0x3933A0).RCast(); + HookAttach(&(PVOID&)o_pLoadAINFile, (PVOID)h_LoadAINFile); Cvar_ns_ai_dumpAINfileFromLoad = new ConVar( "ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk");