From fcb4849b3cbf0883c2e94cd3022198c181461330 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Wed, 8 Jul 2015 21:39:28 -0400 Subject: [PATCH 01/44] S2 WiP --- AMBuildScript | 25 +- configure.py | 2 + core/ISmmPluginExt.h | 1 + core/gamedll_bridge.cpp | 4 + core/metamod.cpp | 40 ++- core/metamod.h | 2 +- core/metamod_console.cpp | 10 +- core/metamod_console.h | 2 +- core/provider/provider_ep2.cpp | 59 +++- core/provider/provider_ep2.h | 1 + core/vsp_bridge.cpp | 7 +- loader2/AMBuilder | 20 ++ loader2/gamedll.cpp | 607 +++++++++++++++++++++++++++++++++ loader2/gamedll.h | 39 +++ loader2/loader2.cpp | 232 +++++++++++++ loader2/loader2.h | 100 ++++++ loader2/utility.cpp | 546 +++++++++++++++++++++++++++++ loader2/utility.h | 70 ++++ public/loader_bridge.h | 70 ++++ public/loader_public.h | 58 ++++ 20 files changed, 1864 insertions(+), 31 deletions(-) create mode 100644 loader2/AMBuilder create mode 100644 loader2/gamedll.cpp create mode 100644 loader2/gamedll.h create mode 100644 loader2/loader2.cpp create mode 100644 loader2/loader2.h create mode 100644 loader2/utility.cpp create mode 100644 loader2/utility.h create mode 100644 public/loader_bridge.h create mode 100644 public/loader_public.h diff --git a/AMBuildScript b/AMBuildScript index 9a5bf77..4f50230 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -38,6 +38,7 @@ PossibleSDKs = { 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), + 's2': SDK('HL2SDKS2', '2.s2', '22', 'SOURCE2', WinOnly, 's2'), } def ResolveEnvPath(env, folder): @@ -112,6 +113,9 @@ class MMSConfig(object): cfg = builder.DetectCompilers() cxx = cfg.cxx + if builder.options.source2 == '1': + cfg.defines += ['SOURCE2_BUILD=1'] + if cxx.behavior == 'gcc': cfg.defines += [ 'stricmp=strcasecmp', @@ -246,7 +250,7 @@ class MMSConfig(object): compiler.cxxincludes += [ os.path.join(context.currentSourcePath), os.path.join(context.currentSourcePath, 'sourcehook'), - os.path.join(context.sourcePath, 'loader'), + os.path.join(context.sourcePath, 'public', 'loader'), ] defines = ['SE_' + self.sdks[i].define + '=' + self.sdks[i].code for i in self.sdks] @@ -278,13 +282,13 @@ class MMSConfig(object): else: compiler.defines += ['COMPILER_GCC'] - if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: + if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota', 's2']: if builder.target_platform in ['linux', 'mac']: compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] - + if sdk.name == 'csgo' and builder.target_platform == 'linux': compiler.linkflags += ['-lstdc++'] - + for path in paths: compiler.cxxincludes += [os.path.join(sdk.path, *path)] @@ -335,7 +339,7 @@ class MMSConfig(object): else: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a'))] - if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']: + if sdk.name in ['blade', 'insurgency', 'csgo', 'dota', 's2']: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))] binary = self.LibraryBuilder(compiler, name) @@ -345,7 +349,7 @@ class MMSConfig(object): compiler.linkflags[0:0] = ['-lm'] if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2']: dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] - elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']: + elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota', 's2']: dynamic_libs = ['libtier0.so', 'libvstdlib.so'] else: dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] @@ -354,7 +358,7 @@ class MMSConfig(object): dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] elif builder.target_platform == 'windows': libs = ['tier0', 'tier1', 'vstdlib'] - if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']: + if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota', 's2']: libs.append('interfaces') for lib in libs: lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' @@ -391,9 +395,10 @@ if MMS.use_auto_versioning(): ) BuildScripts = [ - 'loader/AMBuilder', - 'core-legacy/AMBuilder', - 'core/AMBuilder', +# 'loader/AMBuilder', + 'loader2/AMBuilder', + 'core-legacy/AMBuilder', + 'core/AMBuilder', ] if builder.backend == 'amb2': diff --git a/configure.py b/configure.py index 3b3b313..e9a2e23 100644 --- a/configure.py +++ b/configure.py @@ -23,4 +23,6 @@ run.options.add_option('--enable-optimize', action='store_const', const='1', des run.options.add_option('-s', '--sdks', default='all', dest='sdks', help='Build against specified SDKs; valid args are "all", "present", or ' 'comma-delimited list of engine names (default: %default)') +run.options.add_option('--source2-build', action='store_const', const='1', dest='source2', + help='Build loader for Source2') run.Configure() diff --git a/core/ISmmPluginExt.h b/core/ISmmPluginExt.h index 4f245a5..31b6cb2 100644 --- a/core/ISmmPluginExt.h +++ b/core/ISmmPluginExt.h @@ -59,6 +59,7 @@ #define SOURCE_ENGINE_INSURGENCY 21 /**< Insurgency */ #define SOURCE_ENGINE_CONTAGION 22 /**< Contagion */ #define SOURCE_ENGINE_BMS 23 /**< Black Mesa Multiplayer */ +#define SOURCE_ENGINE_SOURCE2 24 #define METAMOD_PLAPI_VERSION 15 /**< Version of this header file */ #define METAMOD_PLAPI_NAME "ISmmPlugin" /**< Name of the plugin interface */ diff --git a/core/gamedll_bridge.cpp b/core/gamedll_bridge.cpp index 21d730f..8efe541 100644 --- a/core/gamedll_bridge.cpp +++ b/core/gamedll_bridge.cpp @@ -63,7 +63,11 @@ public: SourceHook::MemFuncInfo mfi; mfi.isVirtual = false; +#if SOURCE_ENGINE == SE_SOURCE2 + SourceHook::GetFuncInfo(&IServerGameDLL::Shutdown, mfi); +#else SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi); +#endif assert(mfi.isVirtual); assert(mfi.vtbloffs == 0); assert(mfi.thisptroffs == 0); diff --git a/core/metamod.cpp b/core/metamod.cpp index 9d9fc0b..9581dd6 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -98,7 +98,6 @@ static ConVar *mm_basedir = NULL; static CreateInterfaceFn engine_factory = NULL; static CreateInterfaceFn physics_factory = NULL; static CreateInterfaceFn filesystem_factory = NULL; -static CGlobalVars *gpGlobals = NULL; static CHookManagerAutoGen g_SH_HookManagerAutoGen(&g_SourceHook); static META_RES last_meta_res; static IServerPluginCallbacks *vsp_callbacks = NULL; @@ -143,6 +142,21 @@ SourceMM::ISmmAPI *g_pMetamod = &g_Metamod; } \ } +#if SOURCE_ENGINE == SE_SOURCE2 +void meta_game_init(const CCommand &args) +{ + Handler_GameInit(); +} +void meta_level_init(const CCommand &args) +{ + Handler_LevelInit("dummy_level", "", "", "", false, false); +} +void meta_level_shutdown(const CCommand &args) +{ + Handler_LevelShutdown(); +} +#endif + /* Initialize everything here */ void mm_InitializeForLoad() @@ -157,6 +171,7 @@ mm_InitializeForLoad() */ in_first_level = true; +#if SOURCE_ENGINE != SE_SOURCE2 SourceHook::MemFuncInfo info; if (!provider->GetHookInfo(ProvidedHook_GameInit, &info)) @@ -179,6 +194,7 @@ mm_InitializeForLoad() } SH_MANUALHOOK_RECONFIGURE(SGD_LevelShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs); SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelShutdown, server, Handler_LevelShutdown, true); +#endif } bool @@ -411,6 +427,15 @@ DoInitialPluginLoads() mm_LoadPlugins(filepath, vdfpath); } +ConVar *net_maxroutable; +ConCommand *map; +extern ConCommand meta_local_cmd; + +CON_COMMAND(meta_test, "") +{ + Msg("hi\n"); +} + void mm_StartupMetamod(bool is_vsp_load) { @@ -422,6 +447,17 @@ mm_StartupMetamod(bool is_vsp_load) METAMOD_VERSION, is_vsp_load ? "V" : ""); + net_maxroutable = g_pCVar->FindVar("net_maxroutable"); + map = g_pCVar->FindCommand("logaddress_add"); + meta_local_cmd.AddFlags(0); + meta_test_command.AddFlags(0); + CCommand cmd; + cmd.Tokenize("logaddress_add 192.168.5.9:33333"); + map->Dispatch(CCommandContext(0), cmd); + + Msg("logaddress_add is at 0x%p\n", map); + Msg("meta_local_cmd is at 0x%p\n", &meta_local_cmd); + metamod_version = provider->CreateConVar("metamod_version", METAMOD_VERSION, "Metamod:Source Version", @@ -773,7 +809,7 @@ size_t MetamodSource::PathFormat(char *buffer, size_t len, const char *fmt, ...) return mylen; } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void MetamodSource::ClientConPrintf(int clientIndex, const char *fmt, ...) { va_list ap; diff --git a/core/metamod.h b/core/metamod.h index 07a2b38..c7e1057 100644 --- a/core/metamod.h +++ b/core/metamod.h @@ -76,7 +76,7 @@ public: void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret); const char *GetBaseDir(); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 // Shim void ClientConPrintf(int clientIndex, const char *fmt, ...); #endif diff --git a/core/metamod_console.cpp b/core/metamod_console.cpp index 2bd9c86..392422c 100644 --- a/core/metamod_console.cpp +++ b/core/metamod_console.cpp @@ -44,7 +44,7 @@ using namespace SourceHook; #define CLIENT_CONMSG g_Metamod.ClientConPrintf template -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void CMDMSG(int client, const char *pMsg, Ts ... ts) #else void CMDMSG(edict_t *client, const char *pMsg, Ts ... ts) @@ -100,11 +100,13 @@ void CMDMSG(edict_t *client, const char *pMsg, Ts ... ts) #define MMS_ENGINE_NAME "Counter-Strike: Global Offensive (2012)" #elif SOURCE_ENGINE == SE_DOTA #define MMS_ENGINE_NAME "Dota 2 (2013)" +#elif SOURCE_ENGINE == SE_SOURCE2 +#define MMS_ENGINE_NAME "Source 2" #else #error "SOURCE_ENGINE not defined to a known value" #endif -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 static void ReplyCredits(int client = 0) #else static void ReplyCredits(edict_t *client = nullptr) @@ -118,7 +120,7 @@ static void ReplyCredits(edict_t *client = nullptr) CMDMSG(client, "http://www.metamodsource.net/\n"); } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 static void ReplyVersion(int client = 0) #else static void ReplyVersion(edict_t *client = nullptr) @@ -698,7 +700,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info) return true; } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 bool Command_ClientMeta(int client, IMetamodSourceCommandInfo *info) #else bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info) diff --git a/core/metamod_console.h b/core/metamod_console.h index ef3d529..20e5bd7 100644 --- a/core/metamod_console.h +++ b/core/metamod_console.h @@ -31,7 +31,7 @@ #include "metamod_provider.h" bool Command_Meta(IMetamodSourceCommandInfo *info); -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 bool Command_ClientMeta(int client, IMetamodSourceCommandInfo *info); #else bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info); diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index b5c2c2c..bb9336f 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -62,9 +62,18 @@ DLL_IMPORT ICommandLine *CommandLine(); /* Functions */ void CacheUserMessages(); void Detour_Error(const tchar *pMsg, ...); -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void ClientCommand(CEntityIndex index, const CCommand &args); +#if SOURCE_ENGINE == SE_DOTA void LocalCommand_Meta(const CCommandContext &context, const CCommand &args); +#else +void LocalCommand_Meta(const CCommand &args); +#endif +#if SOURCE_ENGINE == SE_SOURCE2 +void meta_game_init(const CCommand &args); +void meta_level_init(const CCommand &args); +void meta_level_shutdown(const CCommand &args); +#endif #elif SOURCE_ENGINE >= SE_ORANGEBOX void ClientCommand(edict_t *pEdict, const CCommand &args); void LocalCommand_Meta(const CCommand &args); @@ -83,12 +92,21 @@ static jmp_buf usermsg_end; ICvar *icvar = NULL; IFileSystem *baseFs = NULL; IServerGameDLL *server = NULL; +#if SOURCE_ENGINE == SE_SOURCE2 +static ISource2ServerConfig *serverconfig = NULL; +#endif IVEngineServer *engine = NULL; IServerGameClients *gameclients = NULL; +CGlobalVars *gpGlobals = NULL; IMetamodSourceProvider *provider = &g_Ep1Provider; ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options"); +#if SOURCE_ENGINE == SE_SOURCE2 +ConCommand _meta_game_init("meta_game_init", meta_game_init); +ConCommand _meta_level_init("meta_level_init", meta_level_init); +ConCommand _meta_level_shutdown("meta_level_shutdown", meta_level_shutdown); +#endif -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CEntityIndex, const CCommand &); #elif SOURCE_ENGINE >= SE_ORANGEBOX SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &); @@ -114,6 +132,10 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, DisplayError("Could not find IVEngineServer! Metamod cannot load."); return; } +#if SOURCE_ENGINE == SE_SOURCE2 + gpGlobals = engine->GetServerGlobals(); + serverconfig = (ISource2ServerConfig *) ((serverFactory) (INTERFACEVERSION_SERVERCONFIG, NULL)); +#endif #if SOURCE_ENGINE >= SE_ORANGEBOX icvar = (ICvar *)((engineFactory)(CVAR_INTERFACE_VERSION, NULL)); #else @@ -125,12 +147,15 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, return; } - +#if SOURCE_ENGINE == SE_SOURCE2 + gameclients = (IServerGameClients *)(serverFactory(INTERFACEVERSION_SERVERGAMECLIENTS, NULL)); +#else if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL))) == NULL) { gameclients = (IServerGameClients *)(serverFactory("ServerGameClients004", NULL)); } +#endif baseFs = (IFileSystem *)((engineFactory)(FILESYSTEM_INTERFACE_VERSION, NULL)); if (baseFs == NULL) @@ -142,7 +167,8 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, g_pCVar = icvar; #endif - g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); + ConVar_Register(0, &g_SMConVarAccessor); + //g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); CacheUserMessages(); @@ -163,6 +189,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, void BaseProvider::Notify_DLLShutdown_Pre() { + g_SMConVarAccessor.RemoveMetamodCommands(); #if SOURCE_ENGINE == SE_DARKMESSIAH @@ -180,8 +207,8 @@ bool BaseProvider::IsRemotePrintingAvailable() void BaseProvider::ClientConsolePrint(edict_t *pEdict, const char *message) { -#if SOURCE_ENGINE == SE_DOTA - int client = (int)(pEdict - g_Metamod.GetCGlobals()->pEdicts); +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 + int client = (int)(pEdict - gpGlobals->pEdicts); engine->ClientPrintf(client, message); #else engine->ClientPrintf(pEdict, message); @@ -264,6 +291,7 @@ bool BaseProvider::LogMessage(const char *buffer) bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) { +#if SOURCE_ENGINE != SE_SOURCE2 SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; if (hook == ProvidedHook_LevelInit) @@ -282,6 +310,9 @@ bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInf *pInfo = mfi; return (mfi.thisptroffs >= 0); +#else + return false; +#endif } void BaseProvider::DisplayError(const char *fmt, ...) @@ -293,7 +324,11 @@ void BaseProvider::DisplayError(const char *fmt, ...) UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); +#if SOURCE_ENGINE == SE_SOURCE2 + Msg("ERROR: %s", buffer); +#else Error("%s", buffer); +#endif } void BaseProvider::DisplayWarning(const char *fmt, ...) @@ -325,7 +360,7 @@ void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand) int BaseProvider::GetUserMessageCount() { -#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 return -1; #else return (int)usermsgs_list.size(); @@ -371,7 +406,7 @@ void BaseProvider::GetGamePath(char *pszBuffer, int len) const char *BaseProvider::GetGameDescription() { - return server->GetGameDescription(); + return serverconfig->GetGameDescription(); } int BaseProvider::DetermineSourceEngine() @@ -416,6 +451,8 @@ int BaseProvider::DetermineSourceEngine() return SOURCE_ENGINE_DOTA; #elif SOURCE_ENGINE == SE_BMS return SOURCE_ENGINE_BMS; +#elif SOURCE_ENGINE == SE_SOURCE2 + return SOURCE_ENGINE_SOURCE2; #else #error "SOURCE_ENGINE not defined to a known value" #endif @@ -529,7 +566,7 @@ public: }; #endif -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA// || SOURCE_ENGINE == SE_SOURCE2 void LocalCommand_Meta(const CCommandContext &context, const CCommand &args) { GlobCommand cmd(&args); @@ -545,7 +582,7 @@ void LocalCommand_Meta() Command_Meta(&cmd); } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void ClientCommand(CEntityIndex index, const CCommand &_cmd) { int client = index.Get(); @@ -568,7 +605,7 @@ void ClientCommand(edict_t *client) RETURN_META(MRES_IGNORED); } -#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void CacheUserMessages() { diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index b2f424c..c83522c 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -83,6 +83,7 @@ extern IVEngineServer *engine; extern IServerGameDLL *server; extern IServerGameClients *gameclients; extern ICvar *icvar; +extern CGlobalVars *gpGlobals; #endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_ diff --git a/core/vsp_bridge.cpp b/core/vsp_bridge.cpp index ce76931..9842487 100644 --- a/core/vsp_bridge.cpp +++ b/core/vsp_bridge.cpp @@ -46,7 +46,7 @@ ConCommand *g_plugin_unload = NULL; bool g_bIsTryingToUnload; SourceHook::String vsp_desc("Metamod:Source"); -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void InterceptPluginUnloads(const CCommandContext &context, const CCommand &args) #elif SOURCE_ENGINE >= SE_ORANGEBOX void InterceptPluginUnloads(const CCommand &args) @@ -57,7 +57,7 @@ void InterceptPluginUnloads() g_bIsTryingToUnload = true; } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 void InterceptPluginUnloads_Post(const CCommandContext &context, const CCommand &args) #elif SOURCE_ENGINE >= SE_ORANGEBOX void InterceptPluginUnloads_Post(const CCommand &args) @@ -164,11 +164,14 @@ public: virtual void Unload() { + // Source2 doesn't have the Error function (nor VSP support). +#if SOURCE_ENGINE != SE_SOURCE2 if (g_bIsTryingToUnload) { Error("Metamod:Source cannot be unloaded from VSP mode. Use \"meta unload\" to unload specific plugins.\n"); return; } +#endif if (g_plugin_unload != NULL) { SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads, false); diff --git a/loader2/AMBuilder b/loader2/AMBuilder new file mode 100644 index 0000000..a40c986 --- /dev/null +++ b/loader2/AMBuilder @@ -0,0 +1,20 @@ +# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: +import os.path + +def configure_library(name, linux_defines): + binary = MMS.Library(builder, name) + binary.compiler.cxxincludes += [os.path.join(builder.sourcePath, 'core', 'sourcehook')] + binary.sources += [ + 'loader2.cpp', + 'gamedll.cpp', + #'serverplugin.cpp', + 'utility.cpp', + ] + + if builder.target_platform == 'linux': + binary.compiler.defines += linux_defines + + nodes = builder.Add(binary) + MMS.binaries += [nodes] + +configure_library('server', ['LIB_PREFIX="lib"', 'LIB_SUFFIX=".so"']) diff --git a/loader2/gamedll.cpp b/loader2/gamedll.cpp new file mode 100644 index 0000000..c81e618 --- /dev/null +++ b/loader2/gamedll.cpp @@ -0,0 +1,607 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include +#include +#include +#include +#include +#include +#include "loader2.h" +#include +#include +#include "utility.h" +#include "gamedll.h" + +class ISource2Server; +class ISource2ServerConfig; + +#define MAX_GAMEDLL_PATHS 10 + +IGameDllBridge* gamedll_bridge = NULL; +static int game_info_detected = 0; +static char game_name[128]; +static char gamedll_paths[MAX_GAMEDLL_PATHS][PLATFORM_MAX_PATH]; +static void *gamedll_libs[MAX_GAMEDLL_PATHS]; +static unsigned int gamedll_path_count = 0; +static void *gamedll_lib = NULL; +static ISource2Server *gamedll_iface = NULL; +static ISource2ServerConfig *config_iface = NULL; +static QueryValveInterface gamedll_qvi = NULL; +static int gamedll_version = 0; +static int is2s_shutdown_index = -1; +static int is2sc_allowdedi_index = 20; +static char mm_path[PLATFORM_MAX_PATH]; + +#if defined _WIN32 +#define SERVER_NAME "server.dll" +#elif defined __APPLE__ +#define SERVER_NAME "server.dylib" +#elif defined __linux__ +#define SERVER_NAME "server" LIB_SUFFIX +#endif + +static bool mm_DetectGameInformation() +{ + char game_path[PLATFORM_MAX_PATH]; + + if (game_info_detected) + return game_info_detected == 1 ? true : false; + + game_info_detected = -1; + + mm_GetGameName(game_name, sizeof(game_name)); + + if (!mm_GetFileOfAddress((void*)mm_DetectGameInformation, mm_path, sizeof(mm_path))) + { + mm_LogFatal("Could not locate Metamod loader library path"); + return false; + } + + if (!mm_ResolvePath(game_name, game_path, sizeof(game_path))) + { + mm_LogFatal("Could not resolve path: %s", game_name); + return false; + } + + FILE *fp; + char gameinfo_path[PLATFORM_MAX_PATH]; + + mm_PathFormat(gameinfo_path, sizeof(gameinfo_path), "%s/gameinfo.gi", game_path); + if ((fp = fopen(gameinfo_path, "rt")) == NULL) + { + mm_LogFatal("Could not read file: %s", gameinfo_path); + return false; + } + + char temp_path[PLATFORM_MAX_PATH]; + char cur_path[PLATFORM_MAX_PATH]; + getcwd(cur_path, sizeof(cur_path)); + + char *ptr; + const char *lptr; + bool search = false; + char buffer[255], key[128], val[128]; + while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL) + { + mm_TrimComments(buffer); + mm_TrimLeft(buffer); + mm_TrimRight(buffer); + + if (stricmp(buffer, "SearchPaths") == 0) + search = true; + + if (!search) + continue; + + mm_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1); + if (stricmp(key, "Game") != 0 && stricmp(key, "GameBin") != 0) + continue; + + if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0) + { + ptr = &val[sizeof("|gameinfo_path|") - 1]; + if (ptr[0] == '.') + ptr++; + lptr = game_path; + } + else + { + ptr = val; + lptr = cur_path; + } + + if (stricmp(key, "GameBin") == 0) + mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../%s/" SERVER_NAME, lptr, ptr); + else if (!ptr[0]) + mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../bin/win32/" SERVER_NAME, lptr); + else + mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../%s/bin/win32/" SERVER_NAME, lptr, ptr); + + if (mm_PathCmp(mm_path, temp_path)) + continue; + + FILE *exists = fopen(temp_path, "rb"); + if (!exists) + continue; + fclose(exists); + + /* exists is still non-NULL... use this as a flag */ + for (unsigned int i = 0; i < gamedll_path_count; i++) + { + if (mm_PathCmp(gamedll_paths[i], temp_path)) + { + exists = NULL; + break; + } + } + + if (!exists) + continue; + + mm_Format(gamedll_paths[gamedll_path_count], + PLATFORM_MAX_PATH, + "%s", + temp_path); + gamedll_path_count++; + + if (gamedll_path_count == MAX_GAMEDLL_PATHS) + break; + } + fclose(fp); + + game_info_detected = 1; + + if (gamedll_path_count == 0) + { + mm_LogFatal("Could not detect any valid game paths in gameinfo.gi"); + return false; + } + + return true; +} + +static void mm_FreeCachedLibraries() +{ + for (unsigned int i = 0; i < gamedll_path_count; i++) + { + if (gamedll_libs[i] == NULL) + continue; + mm_UnloadLibrary(gamedll_libs[i]); + } +} + +static void mm_PatchDllInit(bool patch); +static void mm_PatchDllShutdown(); +static void mm_PatchAllowDedicated(bool patch); +static void mm_PatchConnect(bool patch); + +static void *is2s_orig_init = NULL; +static void *is2s_orig_shutdown = NULL; +static void *is2sc_orig_allowdedi = NULL; +static void *is2sc_orig_connect = NULL; + +class VEmptyClass +{ +}; + +gamedll_bridge_info g_bridge_info; + +// Rough start order +// CreateInterfaceFn (IS2SC) - hook Connect and AllowDedicatedServer +// IS2SC::Connect - save factory pointer. return orig. remove hook. +// IS2SC::AllowDedicatedServer - return true. remove hook. +// CreateInterfaceFn (IS2S) - hook Init and Shutdown +// IS2S::Init - do same as old ISGD::DLLInit, including core load. return orig. remove hook. +// IS2S::Shutdown - <-- this + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + +class ISource2ServerConfig +{ +public: + virtual bool Connect(QueryValveInterface factory) + { + g_bridge_info.engineFactory = factory; + g_bridge_info.fsFactory = factory; + g_bridge_info.physicsFactory = factory; + + + /* Call the original */ + bool result; + { + union + { + bool(VEmptyClass::*mfpnew)(QueryValveInterface factory); +#if defined _WIN32 + void *addr; + } u; + u.addr = is2sc_orig_connect; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = is2sc_orig_connect; + u.s.adjustor = 0; +#endif + result = (((VEmptyClass *) config_iface)->*u.mfpnew)(factory); + } + + mm_PatchConnect(false); + + return result; + } + virtual bool AllowDedicatedServers(int universe) const + { + mm_PatchAllowDedicated(false); + return true; + } +}; + +class ISource2Server +{ +public: + virtual bool Connect(QueryValveInterface factory) { return true; } + virtual void Disconnect() {} + virtual void *QueryInterface(const char *pInterfaceName) { return nullptr; } + + virtual InitReturnVal_t Init() + { + char error[255]; + if (mm_backend == MMBackend_UNKNOWN) + { + mm_LogFatal("Could not detect engine version"); + } + else + { + if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) + { + mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); + } + else + { + typedef IGameDllBridge *(*GetGameDllBridge)(); + GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); + if (get_bridge == NULL) + { + mm_UnloadMetamodLibrary(); + mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); + } + else + { + gamedll_bridge = get_bridge(); + } + } + } + + if (gamedll_bridge) + { + g_bridge_info.pGlobals = nullptr;// pGlobals; + g_bridge_info.dllVersion = gamedll_version; + g_bridge_info.isgd = gamedll_iface; + g_bridge_info.gsFactory = gamedll_qvi; + g_bridge_info.vsp_listener_path = mm_path; + + strcpy(error, "Unknown error"); + if (!gamedll_bridge->DLLInit_Pre(&g_bridge_info, error, sizeof(error))) + { + gamedll_bridge = NULL; + mm_UnloadMetamodLibrary(); + mm_LogFatal("Unknown error loading Metamod for engine %d: %s", mm_backend, error); + } + } + + /* Call the original */ + InitReturnVal_t result; + { + union + { + InitReturnVal_t(VEmptyClass::*mfpnew)(); +#if defined _WIN32 + void *addr; + } u; + u.addr = is2s_orig_init; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = is2s_orig_init; + u.s.adjustor = 0; +#endif + result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); + } + + /** + * :TODO: possible logic hole here, what happens if the gamedll REALLY returns false? + * I'm pretty sure we'll die horribly. + */ + + if (!result) + { + gamedll_bridge->Unload(); + mm_UnloadMetamodLibrary(); + gamedll_bridge = NULL; + } + else if (gamedll_bridge != NULL) + { + gamedll_bridge->DLLInit_Post(&is2s_shutdown_index); + assert(is2s_shutdown_index != -1); + mm_PatchDllShutdown(); + } + + mm_PatchDllInit(false); + + return result; + } + + virtual void Shutdown() + { + gamedll_bridge->Unload(); + gamedll_bridge = NULL; + mm_UnloadMetamodLibrary(); + + /* Call original function */ + { + union + { + void (VEmptyClass::*mfpnew)(); +#if defined _WIN32 + void *addr; + } u; + u.addr = is2s_orig_shutdown; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = is2s_orig_shutdown; + u.s.adjustor = 0; +#endif + (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); + } + + mm_UnloadLibrary(gamedll_lib); + gamedll_lib = NULL; + } +}; + +static ISource2Server is2s_thunk; +static ISource2ServerConfig is2sc_thunk; + +static void mm_PatchDllInit(bool patch) +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2Server::Init, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **)*(void **)&is2s_thunk; + vtable_dest = (void **)*(void **)gamedll_iface; + + SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], + sizeof(void*), + SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); + + if (patch) + { + assert(is2s_orig_init == NULL); + is2s_orig_init = vtable_dest[mfp.vtblindex]; + vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2s_orig_init != NULL); + vtable_dest[mfp.vtblindex] = is2s_orig_init; + is2s_orig_init = NULL; + } +} + +static void mm_PatchDllShutdown() +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + mfp.isVirtual = false; + SourceHook::GetFuncInfo(&ISource2Server::Shutdown, mfp); + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **)*(void **)&is2s_thunk; + vtable_dest = (void **)*(void **)gamedll_iface; + + is2s_orig_shutdown = vtable_dest[is2s_shutdown_index]; + vtable_dest[is2s_shutdown_index] = vtable_src[mfp.vtblindex]; +} + +static void mm_PatchAllowDedicated(bool patch) +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2ServerConfig::AllowDedicatedServers, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; + + SourceHook::SetMemAccess(&vtable_dest[is2sc_allowdedi_index], + sizeof(void*), + SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + if (patch) + { + assert(is2sc_orig_allowdedi == NULL); + is2sc_orig_allowdedi = vtable_dest[is2sc_allowdedi_index]; + vtable_dest[is2sc_allowdedi_index] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2sc_orig_allowdedi != NULL); + vtable_dest[is2sc_allowdedi_index] = is2sc_orig_allowdedi; + is2sc_orig_allowdedi = NULL; + } +} + +static void mm_PatchConnect(bool patch) +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2ServerConfig::Connect, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; + + SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], + sizeof(void*), + SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + if (patch) + { + assert(is2sc_orig_connect == NULL); + is2sc_orig_connect = vtable_dest[mfp.vtblindex]; + vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2sc_orig_connect != NULL); + vtable_dest[mfp.vtblindex] = is2sc_orig_connect; + is2sc_orig_connect = NULL; + } +} + +enum ServerIface +{ + Other, + ServerConfig, + Server +}; + +void * +mm_GameDllRequest(const char *name, int *ret) +{ + if (strncmp(name, "Source2ServerConfig", 19) == 0) + { + if (!mm_DetectGameInformation()) + { + if (ret != NULL) + *ret = 1; + return NULL; + } + + void *lib; + char error[255]; + void *ptr = NULL; + QueryValveInterface qvi; + for (unsigned int i = 0; i < gamedll_path_count; i++) + { + if (gamedll_libs[i] == NULL) + { + lib = mm_LoadLibrary(gamedll_paths[i], error, sizeof(error)); + if (lib == NULL) + continue; + gamedll_libs[i] = lib; + } + lib = gamedll_libs[i]; + qvi = (QueryValveInterface)mm_GetLibAddress(lib, "CreateInterface"); + if (qvi == NULL) + continue; + ptr = qvi(name, ret); + if (ptr != NULL) + { + gamedll_libs[i] = NULL; + break; + } + } + + if (ptr != NULL) + { + mm_FreeCachedLibraries(); + gamedll_lib = lib; + config_iface = (ISource2ServerConfig *) ptr; + gamedll_qvi = qvi; + + mm_PatchConnect(true); + mm_PatchAllowDedicated(true); + + if (ret != NULL) + *ret = 0; + return ptr; + } + } + else if (strncmp(name, "Source2Server0", 14) == 0) + { + gamedll_iface = (ISource2Server *)gamedll_qvi(name, ret); + gamedll_version = atoi(&name[13]); + mm_PatchDllInit(true); + + if (ret != NULL) + *ret = 0; + return gamedll_iface; + } + else if (gamedll_lib != NULL && gamedll_bridge == NULL) + { + return gamedll_qvi(name, ret); + } + else if (game_info_detected == 0) + { + mm_LogFatal("Received interface request too early: %s", name); + } + + if (ret != NULL) + *ret = 1; + return NULL; +} + diff --git a/loader2/gamedll.h b/loader2/gamedll.h new file mode 100644 index 0000000..1248ef8 --- /dev/null +++ b/loader2/gamedll.h @@ -0,0 +1,39 @@ +/** + * vim: set ts=4 : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ +#define _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ + +#include "loader_bridge.h" + +extern void * +mm_GameDllRequest(const char *name, int *ret); + +extern IGameDllBridge* gamedll_bridge; + +#endif /* _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ */ + diff --git a/loader2/loader2.cpp b/loader2/loader2.cpp new file mode 100644 index 0000000..e177f38 --- /dev/null +++ b/loader2/loader2.cpp @@ -0,0 +1,232 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include +#include +#include +#include +#include +#include +#include "loader2.h" +#include "gamedll.h" +#include "utility.h" +#if defined __APPLE__ +#include +#endif + +static HMODULE mm_library = NULL; +static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log"; +MetamodBackend mm_backend = MMBackend_Source2; + +extern void +mm_LogFatal(const char *message, ...) +{ + FILE *fp; + time_t t; + va_list ap; + char header[256]; + + fp = fopen(mm_fatal_logfile, "at"); + if (!fp && (fp = fopen("metamod-fatal.log", "at")) == NULL) + return; + + t = time(NULL); + strftime(header, sizeof(header), "%m/%d/%Y - %H:%M:%S", localtime(&t)); + fprintf(fp, "L %s: ", header); + + va_start(ap, message); + vfprintf(fp, message, ap); + va_end(ap); + + fprintf(fp, "\n"); + + fclose(fp); +} + +#if defined _WIN32 +#define LIBRARY_EXT ".dll" +#define LIBRARY_MINEXT ".dll" +#elif defined __APPLE__ +#define LIBRARY_EXT ".dylib" +#define LIBRARY_MINEXT ".dylib" +#elif defined __linux__ +#define LIBRARY_EXT LIB_SUFFIX +#define LIBRARY_MINEXT ".so" +#endif + +bool +mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength) +{ + size_t len, temp_len; + char mm_path[PLATFORM_MAX_PATH * 2]; + + /* Get our path */ + if (!mm_GetFileOfAddress((void*)mm_GetFileOfAddress, mm_path, sizeof(mm_path))) + return false; + + len = strlen(mm_path); + temp_len = strlen("server" LIBRARY_EXT); + if (len < temp_len) + return false; + + /* Build log file name */ + mm_path[len - temp_len] = '\0'; + mm_Format(mm_fatal_logfile, + sizeof(mm_fatal_logfile), + "%smetamod-fatal.log", + mm_path); + + /* Replace server2.dll with the new binary we want */ + mm_Format(&mm_path[len - temp_len], + sizeof(mm_path) - (len - temp_len), + "metamod.2.s2" LIBRARY_MINEXT); + + mm_library = (HMODULE)mm_LoadLibrary(mm_path, buffer, maxlength); + + return (mm_library != NULL); +} + +void +mm_UnloadMetamodLibrary() +{ + mm_UnloadLibrary(mm_library); + mm_library = NULL; +} + +#if defined _WIN32 +#define EXPORT extern "C" __declspec(dllexport) +#elif defined __GNUC__ +#if __GNUC__ == 4 +#define EXPORT extern "C" __attribute__ ((visibility("default"))) +#else +#define EXPORT extern "C" +#endif +#endif + +EXPORT void * +CreateInterface(const char *name, int *ret) +{ + void *ptr; + if (gamedll_bridge == NULL) + { + /* Load as gamedll */ + ptr = mm_GameDllRequest(name, ret); + } + else + { + /* If we've got a gamedll bridge, forward the request. */ + return gamedll_bridge->QueryInterface(name, ret); + } + + if (ret != NULL) + *ret = (ptr != NULL) ? 0 : 1; + + return ptr; +} + +void * +mm_GetProcAddress(const char *name) +{ + return mm_GetLibAddress(mm_library, name); +} + +void +mm_GetGameName(char *buffer, size_t size) +{ + buffer[0] = '\0'; + +#if defined _WIN32 + static char game[128]; + + LPWSTR pCmdLine = GetCommandLineW(); + int argc; + LPWSTR *wargv = CommandLineToArgvW(pCmdLine, &argc); + for (int i = 0; i < argc; ++i) + { + if (wcscmp(wargv[i], L"-game") != 0) + continue; + + if (++i >= argc) + break; + + wcstombs(buffer, wargv[i], size); + buffer[size-1] = '\0'; + break; + } + + LocalFree(wargv); + +#elif defined __APPLE__ + int argc = *_NSGetArgc(); + char **argv = *_NSGetArgv(); + for (int i = 0; i < argc; ++i) + { + if (strcmp(argv[i], "-game") != 0) + continue; + + if (++i >= argc) + break; + + strncpy(buffer, argv[i], size); + buffer[size-1] = '\0'; + break; + } + +#elif defined __linux__ + FILE *pFile = fopen("/proc/self/cmdline", "rb"); + if (pFile) + { + char *arg = NULL; + size_t argsize = 0; + bool bNextIsGame = false; + + while (getdelim(&arg, &argsize, 0, pFile) != -1) + { + if (bNextIsGame) + { + strncpy(buffer, arg, size); + buffer[size-1] = '\0'; + break; + } + + if (strcmp(arg, "-game") == 0) + { + bNextIsGame = true; + } + } + + free(arg); + fclose(pFile); + } +#else +#error unsupported platform +#endif + + if (buffer[0] == 0) + { + strncpy(buffer, "dota", size); + } +} + diff --git a/loader2/loader2.h b/loader2/loader2.h new file mode 100644 index 0000000..ea16fb9 --- /dev/null +++ b/loader2/loader2.h @@ -0,0 +1,100 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_H_ +#define _INCLUDE_METAMOD_SOURCE_LOADER_H_ + +// System +#define SH_SYS_WIN32 1 +#define SH_SYS_LINUX 2 +#define SH_SYS_APPLE 3 + +// Platform +#define SH_XP_POSIX 10 +#define SH_XP_WINAPI 20 + +// Compiler +#define SH_COMP_GCC 1 +#define SH_COMP_MSVC 2 + +#if defined WIN32 +#define SH_SYS SH_SYS_WIN32 +#define SH_XP SH_XP_WINAPI +#define SH_COMP SH_COMP_MSVC +#define WINDOWS_LEAN_AND_MEAN +#include +#include +#define PLATFORM_MAX_PATH MAX_PATH +#define PATH_SEP_STR "\\" +#define PATH_SEP_CHAR '\\' +#define ALT_SEP_CHAR '/' +#elif defined __linux__ || defined __APPLE__ +#if defined __linux__ +#define SH_SYS SH_SYS_LINUX +#elif defined __APPLE__ +#define SH_SYS SH_SYS_APPLE +#endif +#define SH_XP SH_XP_POSIX +#define SH_COMP SH_COMP_GCC +#include +#include +#include +#include +#if SH_SYS == SH_SYS_APPLE +#include +#endif +typedef void * HMODULE; +#define PLATFORM_MAX_PATH PATH_MAX +#define PATH_SEP_STR "/" +#define PATH_SEP_CHAR '/' +#define ALT_SEP_CHAR '\\' +#else +#error "OS detection failed" +#endif + +#include +#include "loader_bridge.h" + +#define SH_PTRSIZE sizeof(void*) + +extern bool +mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength); + +extern void * +mm_GetProcAddress(const char *name); + +extern void +mm_UnloadMetamodLibrary(); + +extern void +mm_LogFatal(const char *message, ...); + +extern void +mm_GetGameName(char *buffer, size_t size); + +extern MetamodBackend mm_backend; + +#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_H_ */ + diff --git a/loader2/utility.cpp b/loader2/utility.cpp new file mode 100644 index 0000000..ce75c5c --- /dev/null +++ b/loader2/utility.cpp @@ -0,0 +1,546 @@ +/** + * vim: set ts=4 : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include "loader2.h" +#include "utility.h" + +#if defined __linux__ +#include + +#define PAGE_SIZE 4096 +#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) +#elif defined __APPLE__ +#include +#endif + +#if defined _WIN32 +static void +mm_GetPlatformError(char *buffer, size_t maxlength) +{ + DWORD dw = GetLastError(); + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)buffer, + maxlength, + NULL); +} +#endif + + +size_t +mm_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params) +{ + size_t len = vsnprintf(buffer, maxlength, fmt, params); + + if (len >= maxlength) + { + len = maxlength - 1; + buffer[len] = '\0'; + } + + return len; +} + +size_t +mm_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + size_t len; + va_list ap; + + va_start(ap, fmt); + len = mm_FormatArgs(buffer, maxlength, fmt, ap); + va_end(ap); + + return len; +} + +size_t +mm_PathFormat(char *buffer, size_t maxlen, const char *fmt, ...) +{ + size_t len; + va_list ap; + + va_start(ap, fmt); + len = mm_FormatArgs(buffer, maxlen, fmt, ap); + va_end(ap); + + for (size_t i = 0; i < len; i++) + { + if (buffer[i] == ALT_SEP_CHAR) + buffer[i] = PATH_SEP_CHAR; + } + + return len; +} + +void +mm_TrimLeft(char *buffer) +{ + /* Let's think of this as our iterator */ + char *i = buffer; + + /* Make sure the buffer isn't null */ + if (i && *i) + { + /* Add up number of whitespace characters */ + while(isspace((unsigned char) *i)) + i++; + + /* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */ + if (i != buffer) + memmove(buffer, i, (strlen(i) + 1) * sizeof(char)); + } +} + +void +mm_TrimRight(char *buffer) +{ + /* Make sure buffer isn't null */ + if (buffer) + { + size_t len = strlen(buffer); + + /* Loop through buffer backwards while replacing whitespace chars with null chars */ + for (size_t i = len - 1; i < len; i--) + { + if (isspace((unsigned char) buffer[i])) + buffer[i] = '\0'; + else + break; + } + } +} + +/* :TODO: this should skip string literals */ +void +mm_TrimComments(char *buffer) +{ + int num_sc = 0; + size_t len = strlen(buffer); + if (buffer) + { + for (int i = len - 1; i >= 0; i--) + { + if (buffer[i] == '/') + { + if (++num_sc >= 2 && i==0) + { + buffer[i] = '\0'; + return; + } + } + else + { + if (num_sc >= 2) + { + buffer[i] = '\0'; + return; + } + num_sc = 0; + } + /* size_t won't go below 0, manually break out */ + if (i == 0) + break; + + } + } +} + +void +mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2) +{ + size_t start; + size_t len = strlen(str); + + for (start = 0; start < len; start++) + { + if (!isspace(str[start])) + break; + } + + size_t end; + for (end = start; end < len; end++) + { + if (isspace(str[end])) + break; + } + + size_t i, c = 0; + for (i = start; i < end; i++, c++) + { + if (c >= len1) + break; + buf1[c] = str[i]; + } + buf1[c] = '\0'; + + for (start = end; start < len; start++) + { + if (!isspace(str[start])) + break; + } + + for (c = 0; start < len; start++, c++) + { + if (c >= len2) + break; + buf2[c] = str[start]; + } + buf2[c] = '\0'; +} + +bool +mm_PathCmp(const char *path1, const char *path2) +{ + size_t pos1 = 0, pos2 = 0; + + while (true) + { + if (path1[pos1] == '\0' || path2[pos2] == '\0') + return (path1[pos1] == path2[pos2]); + + if (path1[pos1] == PATH_SEP_CHAR) + { + if (path2[pos2] != PATH_SEP_CHAR) + return false; + + /* Look for extra path chars */ + while (path1[++pos1]) + { + if (path1[pos1] != PATH_SEP_CHAR) + break; + } + while (path2[++pos2]) + { + if (path2[pos2] != PATH_SEP_CHAR) + break; + } + continue; + } + + /* If we're at a different non-alphanumeric, the next character MUST match */ + if ((((unsigned)path1[pos1] & 0x80) && path1[pos1] != path2[pos2]) + || + (!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2])) + ) + { + return false; + } + + #ifdef WIN32 + if (toupper(path1[pos1]) != toupper(path2[pos2])) + #else + if (path1[pos1] != path2[pos2]) + #endif + { + return false; + } + + pos1++; + pos2++; + } +} + +bool +mm_ResolvePath(const char *path, char *buffer, size_t maxlength) +{ + char tmp[PLATFORM_MAX_PATH]; + mm_Format(tmp, sizeof(tmp), "../../%s", path); +#if defined _WIN32 + return _fullpath(buffer, tmp, maxlength) != NULL; +#elif defined __linux__ || defined __APPLE__ + assert(maxlength >= PATH_MAX); + return realpath(tmp, buffer) != NULL; +#endif +} + +void * +mm_LoadLibrary(const char *path, char *buffer, size_t maxlength) +{ + void *lib; + +#if defined _WIN32 + lib = (void*)LoadLibrary(path); + + if (lib == NULL) + { + mm_GetPlatformError(buffer, maxlength); + return NULL; + } +#elif defined __linux__ || defined __APPLE__ + lib = dlopen(path, RTLD_NOW); + + if (lib == NULL) + { + mm_Format(buffer, maxlength, "%s", dlerror()); + return NULL; + } +#endif + + return lib; +} + +void * +mm_GetLibAddress(void *lib, const char *name) +{ +#if defined _WIN32 + return GetProcAddress((HMODULE)lib, name); +#elif defined __linux__ || defined __APPLE__ + return dlsym(lib, name); +#endif +} + +void +mm_UnloadLibrary(void *lib) +{ +#if defined _WIN32 + FreeLibrary((HMODULE)lib); +#elif defined __linux__ || defined __APPLE__ + dlclose(lib); +#endif +} + +bool +mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength) +{ +#if defined _WIN32 + MEMORY_BASIC_INFORMATION mem; + if (!VirtualQuery(pAddr, &mem, sizeof(mem))) + return false; + if (mem.AllocationBase == NULL) + return false; + HMODULE dll = (HMODULE)mem.AllocationBase; + GetModuleFileName(dll, (LPTSTR)buffer, maxlength); +#elif defined __linux__ || defined __APPLE__ + Dl_info info; + if (!dladdr(pAddr, &info)) + return false; + if (!info.dli_fbase || !info.dli_fname) + return false; + const char *dllpath = info.dli_fname; + snprintf(buffer, maxlength, "%s", dllpath); +#endif + return true; +} + +struct DynLibInfo +{ + void *baseAddress; + size_t memorySize; +}; + +static bool +mm_GetLibraryInfo(const void *libPtr, DynLibInfo &lib) +{ + uintptr_t baseAddr; + + if (libPtr == NULL) + { + return false; + } + +#ifdef _WIN32 + + MEMORY_BASIC_INFORMATION info; + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *pe; + IMAGE_FILE_HEADER *file; + IMAGE_OPTIONAL_HEADER *opt; + + if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) + { + return false; + } + + baseAddr = reinterpret_cast(info.AllocationBase); + + /* All this is for our insane sanity checks :o */ + dos = reinterpret_cast(baseAddr); + pe = reinterpret_cast(baseAddr + dos->e_lfanew); + file = &pe->FileHeader; + opt = &pe->OptionalHeader; + + /* Check PE magic and signature */ + if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + return false; + } + + /* Check architecture, which is 32-bit/x86 right now + * Should change this for 64-bit if Valve gets their act together + */ + if (file->Machine != IMAGE_FILE_MACHINE_I386) + { + return false; + } + + /* For our purposes, this must be a dynamic library */ + if ((file->Characteristics & IMAGE_FILE_DLL) == 0) + { + return false; + } + + /* Finally, we can do this */ + lib.memorySize = opt->SizeOfImage; + +#elif defined __linux__ + + Dl_info info; + Elf32_Ehdr *file; + Elf32_Phdr *phdr; + uint16_t phdrCount; + + if (!dladdr(libPtr, &info)) + { + return false; + } + + if (!info.dli_fbase || !info.dli_fname) + { + return false; + } + + /* This is for our insane sanity checks :o */ + baseAddr = reinterpret_cast(info.dli_fbase); + file = reinterpret_cast(baseAddr); + + /* Check ELF magic */ + if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) + { + return false; + } + + /* Check ELF version */ + if (file->e_ident[EI_VERSION] != EV_CURRENT) + { + return false; + } + + /* Check ELF architecture, which is 32-bit/x86 right now + * Should change this for 64-bit if Valve gets their act together + */ + if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB) + { + return false; + } + + /* For our purposes, this must be a dynamic library/shared object */ + if (file->e_type != ET_DYN) + { + return false; + } + + phdrCount = file->e_phnum; + phdr = reinterpret_cast(baseAddr + file->e_phoff); + + for (uint16_t i = 0; i < phdrCount; i++) + { + Elf32_Phdr &hdr = phdr[i]; + + /* We only really care about the segment with executable code */ + if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R)) + { + /* From glibc, elf/dl-load.c: + * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) + * & ~(GLRO(dl_pagesize) - 1)); + * + * In glibc, the segment file size is aligned up to the nearest page size and + * added to the virtual address of the segment. We just want the size here. + */ + lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz); + break; + } + } + +#elif defined __APPLE__ + + Dl_info info; + struct mach_header *file; + struct segment_command *seg; + uint32_t cmd_count; + + if (!dladdr(libPtr, &info)) + { + return false; + } + + if (!info.dli_fbase || !info.dli_fname) + { + return false; + } + + /* This is for our insane sanity checks :o */ + baseAddr = (uintptr_t)info.dli_fbase; + file = (struct mach_header *)baseAddr; + + /* Check Mach-O magic */ + if (file->magic != MH_MAGIC) + { + return false; + } + + /* Check architecture (32-bit/x86) */ + if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL) + { + return false; + } + + /* For our purposes, this must be a dynamic library */ + if (file->filetype != MH_DYLIB) + { + return false; + } + + cmd_count = file->ncmds; + seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header)); + + /* Add up memory sizes of mapped segments */ + for (uint32_t i = 0; i < cmd_count; i++) + { + if (seg->cmd == LC_SEGMENT) + { + lib.memorySize += seg->vmsize; + } + + seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize); + } + +#endif + + lib.baseAddress = reinterpret_cast(baseAddr); + + return true; +} diff --git a/loader2/utility.h b/loader2/utility.h new file mode 100644 index 0000000..9d8b40a --- /dev/null +++ b/loader2/utility.h @@ -0,0 +1,70 @@ +/** + * vim: set ts=4 : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2015 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ +#define _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ + +#include + +extern size_t +mm_Format(char *buffer, size_t maxlength, const char *fmt, ...); + +extern void * +mm_LoadLibrary(const char *path, char *buffer, size_t maxlength); + +extern void * +mm_GetLibAddress(void *lib, const char *name); + +extern void +mm_UnloadLibrary(void *lib); + +extern bool +mm_ResolvePath(const char *path, char *buffer, size_t maxlength); + +extern size_t +mm_PathFormat(char *buffer, size_t len, const char *fmt, ...); + +extern void +mm_TrimLeft(char *buffer); + +extern void +mm_TrimRight(char *buffer); + +extern void +mm_TrimComments(char *buffer); + +extern void +mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2); + +extern bool +mm_PathCmp(const char *path1, const char *path2); + +extern bool +mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength); + +#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ */ + diff --git a/public/loader_bridge.h b/public/loader_bridge.h new file mode 100644 index 0000000..07570ce --- /dev/null +++ b/public/loader_bridge.h @@ -0,0 +1,70 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2009 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ +#define _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ + +typedef void* (*QueryValveInterface)(const char *pName, int *pReturnCode); +class IServerPluginCallbacks; + +struct vsp_bridge_info +{ + QueryValveInterface engineFactory; + QueryValveInterface gsFactory; + IServerPluginCallbacks * vsp_callbacks; + unsigned int vsp_version; +}; + +class IVspBridge +{ +public: + virtual bool Load(const vsp_bridge_info *info, char *buffer, size_t maxlength) = 0; + virtual void Unload() = 0; + virtual const char *GetDescription() = 0; +}; + +struct gamedll_bridge_info +{ + QueryValveInterface engineFactory; + QueryValveInterface fsFactory; + QueryValveInterface physicsFactory; + QueryValveInterface gsFactory; + void * pGlobals; + unsigned int dllVersion; + void * isgd; + const char * vsp_listener_path; +}; + +class IGameDllBridge +{ +public: + virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength) = 0; + virtual void DLLInit_Post(int *isgdUnload) = 0; + virtual void *QueryInterface(const char *name, int *ret) = 0; + virtual void Unload() = 0; +}; + +#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ */ + diff --git a/public/loader_public.h b/public/loader_public.h new file mode 100644 index 0000000..18c8536 --- /dev/null +++ b/public/loader_public.h @@ -0,0 +1,58 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ====================================================== + * Metamod:Source + * Copyright (C) 2004-2010 AlliedModders LLC and authors. + * All rights reserved. + * ====================================================== + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef _INCLUDE_METAMOD_LOADER_PUBLIC_H_ +#define _INCLUDE_METAMOD_LOADER_PUBLIC_H_ + +enum MetamodBackend +{ + MMBackend_Episode1 = 0, + MMBackend_DarkMessiah, + MMBackend_Episode2, + MMBackend_BloodyGoodTime, + MMBackend_EYE, + MMBackend_CSS, + MMBackend_Episode2Valve_OBSOLETE, + MMBackend_Left4Dead, + MMBackend_Left4Dead2, + MMBackend_AlienSwarm, + MMBackend_Portal2, + MMBackend_CSGO, + MMBackend_DOTA, + MMBackend_HL2DM, + MMBackend_DODS, + MMBackend_TF2, + MMBackend_NuclearDawn, + MMBackend_SDK2013, + MMBackend_Blade, + MMBackend_Insurgency, + MMBackend_Contagion, + MMBackend_BMS, + MMBackend_Source2, + + MMBackend_UNKNOWN +}; + +#endif // _INCLUDE_METAMOD_LOADER_PUBLIC_H_ \ No newline at end of file From cb8b0fd8d5ec8b72e3a7d360e434c3476a7740b8 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 9 Jul 2015 06:54:44 -0400 Subject: [PATCH 02/44] Remove some testing crap. --- core/metamod.cpp | 20 -------------------- core/provider/provider_ep2.cpp | 3 +-- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 9581dd6..0c501ba 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -427,15 +427,6 @@ DoInitialPluginLoads() mm_LoadPlugins(filepath, vdfpath); } -ConVar *net_maxroutable; -ConCommand *map; -extern ConCommand meta_local_cmd; - -CON_COMMAND(meta_test, "") -{ - Msg("hi\n"); -} - void mm_StartupMetamod(bool is_vsp_load) { @@ -447,17 +438,6 @@ mm_StartupMetamod(bool is_vsp_load) METAMOD_VERSION, is_vsp_load ? "V" : ""); - net_maxroutable = g_pCVar->FindVar("net_maxroutable"); - map = g_pCVar->FindCommand("logaddress_add"); - meta_local_cmd.AddFlags(0); - meta_test_command.AddFlags(0); - CCommand cmd; - cmd.Tokenize("logaddress_add 192.168.5.9:33333"); - map->Dispatch(CCommandContext(0), cmd); - - Msg("logaddress_add is at 0x%p\n", map); - Msg("meta_local_cmd is at 0x%p\n", &meta_local_cmd); - metamod_version = provider->CreateConVar("metamod_version", METAMOD_VERSION, "Metamod:Source Version", diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index bb9336f..8a3a303 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -167,8 +167,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, g_pCVar = icvar; #endif - ConVar_Register(0, &g_SMConVarAccessor); - //g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); + g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); CacheUserMessages(); From 4b75bcb43187a49a63cadc75b605692ad51ee230 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 9 Jul 2015 13:15:41 -0400 Subject: [PATCH 03/44] Renamed s2 -> source2. --- AMBuildScript | 10 +++--- loader/loader_bridge.h | 70 ------------------------------------------ 2 files changed, 5 insertions(+), 75 deletions(-) delete mode 100644 loader/loader_bridge.h diff --git a/AMBuildScript b/AMBuildScript index 4f50230..2ece4a1 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -38,7 +38,7 @@ PossibleSDKs = { 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), - 's2': SDK('HL2SDKS2', '2.s2', '22', 'SOURCE2', WinOnly, 's2'), + 'source2': SDK('HL2SDKS2', '2.s2', '22', 'SOURCE2', WinOnly, 'source2'), } def ResolveEnvPath(env, folder): @@ -282,7 +282,7 @@ class MMSConfig(object): else: compiler.defines += ['COMPILER_GCC'] - if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota', 's2']: + if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota', 'source2']: if builder.target_platform in ['linux', 'mac']: compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] @@ -339,7 +339,7 @@ class MMSConfig(object): else: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a'))] - if sdk.name in ['blade', 'insurgency', 'csgo', 'dota', 's2']: + if sdk.name in ['blade', 'insurgency', 'csgo', 'dota', 'source2']: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))] binary = self.LibraryBuilder(compiler, name) @@ -349,7 +349,7 @@ class MMSConfig(object): compiler.linkflags[0:0] = ['-lm'] if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2']: dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] - elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota', 's2']: + elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota', 'source2']: dynamic_libs = ['libtier0.so', 'libvstdlib.so'] else: dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] @@ -358,7 +358,7 @@ class MMSConfig(object): dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] elif builder.target_platform == 'windows': libs = ['tier0', 'tier1', 'vstdlib'] - if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota', 's2']: + if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota', 'source2']: libs.append('interfaces') for lib in libs: lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' diff --git a/loader/loader_bridge.h b/loader/loader_bridge.h deleted file mode 100644 index 07570ce..0000000 --- a/loader/loader_bridge.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2009 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ -#define _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ - -typedef void* (*QueryValveInterface)(const char *pName, int *pReturnCode); -class IServerPluginCallbacks; - -struct vsp_bridge_info -{ - QueryValveInterface engineFactory; - QueryValveInterface gsFactory; - IServerPluginCallbacks * vsp_callbacks; - unsigned int vsp_version; -}; - -class IVspBridge -{ -public: - virtual bool Load(const vsp_bridge_info *info, char *buffer, size_t maxlength) = 0; - virtual void Unload() = 0; - virtual const char *GetDescription() = 0; -}; - -struct gamedll_bridge_info -{ - QueryValveInterface engineFactory; - QueryValveInterface fsFactory; - QueryValveInterface physicsFactory; - QueryValveInterface gsFactory; - void * pGlobals; - unsigned int dllVersion; - void * isgd; - const char * vsp_listener_path; -}; - -class IGameDllBridge -{ -public: - virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength) = 0; - virtual void DLLInit_Post(int *isgdUnload) = 0; - virtual void *QueryInterface(const char *name, int *ret) = 0; - virtual void Unload() = 0; -}; - -#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ */ - From 30b7be46a84af9c1dcb79e74f16c8d67978945bb Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 9 Jul 2015 14:09:56 -0400 Subject: [PATCH 04/44] Merge loader, loader2. Rename env var HL2SDKS2 -> HL2SDKSOURCE2. --- AMBuildScript | 7 +- core/provider/provider_ep2.cpp | 4 + loader/gamedll.cpp | 428 ++++++++++++++++++-- loader/loader.cpp | 7 +- loader/loader.h | 3 +- {public => loader}/loader_bridge.h | 0 loader/utility.cpp | 10 +- loader/utility.h | 4 +- loader2/AMBuilder | 20 - loader2/gamedll.cpp | 607 ----------------------------- loader2/gamedll.h | 39 -- loader2/loader2.cpp | 232 ----------- loader2/loader2.h | 100 ----- loader2/utility.cpp | 546 -------------------------- loader2/utility.h | 70 ---- public/loader_public.h | 58 --- 16 files changed, 422 insertions(+), 1713 deletions(-) rename {public => loader}/loader_bridge.h (100%) delete mode 100644 loader2/AMBuilder delete mode 100644 loader2/gamedll.cpp delete mode 100644 loader2/gamedll.h delete mode 100644 loader2/loader2.cpp delete mode 100644 loader2/loader2.h delete mode 100644 loader2/utility.cpp delete mode 100644 loader2/utility.h delete mode 100644 public/loader_public.h diff --git a/AMBuildScript b/AMBuildScript index 2ece4a1..d207c37 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -38,7 +38,7 @@ PossibleSDKs = { 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), - 'source2': SDK('HL2SDKS2', '2.s2', '22', 'SOURCE2', WinOnly, 'source2'), + 'source2': SDK('HL2SDKSOURCE2', '2.s2', '22', 'SOURCE2', WinOnly, 'source2'), } def ResolveEnvPath(env, folder): @@ -250,7 +250,7 @@ class MMSConfig(object): compiler.cxxincludes += [ os.path.join(context.currentSourcePath), os.path.join(context.currentSourcePath, 'sourcehook'), - os.path.join(context.sourcePath, 'public', 'loader'), + os.path.join(context.sourcePath, 'loader'), ] defines = ['SE_' + self.sdks[i].define + '=' + self.sdks[i].code for i in self.sdks] @@ -395,8 +395,7 @@ if MMS.use_auto_versioning(): ) BuildScripts = [ -# 'loader/AMBuilder', - 'loader2/AMBuilder', + 'loader/AMBuilder', 'core-legacy/AMBuilder', 'core/AMBuilder', ] diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 8a3a303..41fcfc6 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -405,7 +405,11 @@ void BaseProvider::GetGamePath(char *pszBuffer, int len) const char *BaseProvider::GetGameDescription() { +#if SOURCE_ENGINE == SE_SOURCE2 return serverconfig->GetGameDescription(); +#else + return server->GetGameDescription(); +#endif } int BaseProvider::DetermineSourceEngine() diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 1d46c9f..000f900 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 sw=4 tw=99 noet : * ====================================================== * Metamod:Source - * Copyright (C) 2004-2009 AlliedModders LLC and authors. + * Copyright (C) 2004-2015 AlliedModders LLC and authors. * All rights reserved. * ====================================================== * @@ -36,6 +36,7 @@ #include "gamedll.h" class IServerGameDLL; +class ISource2ServerConfig; #define MAX_GAMEDLL_PATHS 10 @@ -47,10 +48,13 @@ static void *gamedll_libs[MAX_GAMEDLL_PATHS]; static unsigned int gamedll_path_count = 0; static void *gamedll_lib = NULL; static IServerGameDLL *gamedll_iface = NULL; +static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; +static int is2sc_allowdedi_index = 20; static char mm_path[PLATFORM_MAX_PATH]; +static bool g_is_source2 = false; #if defined _WIN32 #define SERVER_NAME "server.dll" @@ -78,7 +82,7 @@ mm_DetectGameInformation() return false; } - if (!mm_ResolvePath(game_name, game_path, sizeof(game_path))) + if (!mm_ResolvePath(game_name, game_path, sizeof(game_path), g_is_source2)) { mm_LogFatal("Could not resolve path: %s", game_name); return false; @@ -87,11 +91,21 @@ mm_DetectGameInformation() FILE *fp; char gameinfo_path[PLATFORM_MAX_PATH]; + bool is_source2 = false; mm_PathFormat(gameinfo_path, sizeof(gameinfo_path), "%s/gameinfo.txt", game_path); if ((fp = fopen(gameinfo_path, "rt")) == NULL) { - mm_LogFatal("Could not read file: %s", gameinfo_path); - return false; + // Try Source2 gameinfo + mm_PathFormat(gameinfo_path, sizeof(gameinfo_path), "%s/gameinfo.gi", game_path); + if ((fp = fopen(gameinfo_path, "rt")) == NULL) + { + mm_LogFatal("Could not read file: %s", gameinfo_path); + return false; + } + else + { + is_source2 = true; + } } char temp_path[PLATFORM_MAX_PATH]; @@ -131,12 +145,14 @@ mm_DetectGameInformation() lptr = cur_path; } + char *pRelPath = is_source2 ? "../../" : ""; + char *pOSDir = is_source2 ? "win32/" : ""; if (stricmp(key, "GameBin") == 0) - mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s/" SERVER_NAME, lptr, ptr); + mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s%s/%s" SERVER_NAME, lptr, pRelPath, ptr, pOSDir); else if (!ptr[0]) - mm_PathFormat(temp_path, sizeof(temp_path), "%s/bin/" SERVER_NAME, lptr); + mm_PathFormat(temp_path, sizeof(temp_path), "%s/%sbin/%s" SERVER_NAME, lptr, pRelPath, pOSDir); else - mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s/bin/" SERVER_NAME, lptr, ptr); + mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s%s/bin/%s" SERVER_NAME, lptr, pRelPath, ptr, pOSDir); if (mm_PathCmp(mm_path, temp_path)) continue; @@ -174,7 +190,7 @@ mm_DetectGameInformation() if (gamedll_path_count == 0) { - mm_LogFatal("Could not detect any valid game paths in gameinfo.txt"); + mm_LogFatal("Could not detect any valid game paths in gameinfo file"); return false; } @@ -198,13 +214,215 @@ mm_PatchDllInit(bool patch); static void mm_PatchDllShutdown(); +static void +mm_PatchAllowDedicated(bool patch); + +static void +mm_PatchConnect(bool patch); + static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; +static void *is2sc_orig_allowdedi = NULL; +static void *is2sc_orig_connect = NULL; class VEmptyClass { }; +gamedll_bridge_info g_bridge_info; + +// Source2 - Rough start order +// CreateInterfaceFn (IS2SC) - hook Connect and AllowDedicatedServer +// IS2SC::Connect - save factory pointer. return orig. remove hook. +// IS2SC::AllowDedicatedServer - return true. remove hook. +// CreateInterfaceFn (IS2S) - hook Init and Shutdown +// IS2S::Init - do same as old ISGD::DLLInit, including core load. return orig. remove hook. +// IS2S::Shutdown - <-- this + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + +class ISource2ServerConfig +{ +public: + virtual bool Connect(QueryValveInterface factory) + { + g_bridge_info.engineFactory = factory; + g_bridge_info.fsFactory = factory; + g_bridge_info.physicsFactory = factory; + + + /* Call the original */ + bool result; + { + union + { + bool(VEmptyClass::*mfpnew)(QueryValveInterface factory); +#if defined _WIN32 + void *addr; + } u; + u.addr = is2sc_orig_connect; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = is2sc_orig_connect; + u.s.adjustor = 0; +#endif + result = (((VEmptyClass *) config_iface)->*u.mfpnew)(factory); + } + + mm_PatchConnect(false); + + return result; + } + virtual bool AllowDedicatedServers(int universe) const + { + mm_PatchAllowDedicated(false); + return true; + } +}; + +class ISource2Server +{ +public: + virtual bool Connect(QueryValveInterface factory) { return true; } + virtual void Disconnect() {} + virtual void *QueryInterface(const char *pInterfaceName) { return nullptr; } + + virtual InitReturnVal_t Init() + { + char error[255]; + if (mm_backend == MMBackend_UNKNOWN) + { + mm_LogFatal("Could not detect engine version"); + } + else + { + if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) + { + mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); + } + else + { + typedef IGameDllBridge *(*GetGameDllBridge)(); + GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); + if (get_bridge == NULL) + { + mm_UnloadMetamodLibrary(); + mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); + } + else + { + gamedll_bridge = get_bridge(); + } + } + } + + if (gamedll_bridge) + { + g_bridge_info.pGlobals = nullptr;// pGlobals; + g_bridge_info.dllVersion = gamedll_version; + g_bridge_info.isgd = gamedll_iface; + g_bridge_info.gsFactory = gamedll_qvi; + g_bridge_info.vsp_listener_path = mm_path; + + strcpy(error, "Unknown error"); + if (!gamedll_bridge->DLLInit_Pre(&g_bridge_info, error, sizeof(error))) + { + gamedll_bridge = NULL; + mm_UnloadMetamodLibrary(); + mm_LogFatal("Unknown error loading Metamod for engine %d: %s", mm_backend, error); + } + } + + /* Call the original */ + InitReturnVal_t result; + { + union + { + InitReturnVal_t(VEmptyClass::*mfpnew)(); +#if defined _WIN32 + void *addr; + } u; + u.addr = isgd_orig_init; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = isgd_orig_init; + u.s.adjustor = 0; +#endif + result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); + } + + /** + * :TODO: possible logic hole here, what happens if the gamedll REALLY returns false? + * I'm pretty sure we'll die horribly. + */ + + if (!result) + { + gamedll_bridge->Unload(); + mm_UnloadMetamodLibrary(); + gamedll_bridge = NULL; + } + else if (gamedll_bridge != NULL) + { + gamedll_bridge->DLLInit_Post(&isgd_shutdown_index); + assert(isgd_shutdown_index != -1); + mm_PatchDllShutdown(); + } + + mm_PatchDllInit(false); + + return result; + } + + virtual void Shutdown() + { + gamedll_bridge->Unload(); + gamedll_bridge = NULL; + mm_UnloadMetamodLibrary(); + + /* Call original function */ + { + union + { + void (VEmptyClass::*mfpnew)(); +#if defined _WIN32 + void *addr; + } u; + u.addr = isgd_orig_shutdown; +#else + struct + { + void *addr; + intptr_t adjustor; + } s; + } u; + u.s.addr = isgd_orig_shutdown; + u.s.adjustor = 0; +#endif + (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); + } + + mm_UnloadLibrary(gamedll_lib); + gamedll_lib = NULL; + } +}; + class IServerGameDLL { public: @@ -244,19 +462,17 @@ public: if (gamedll_bridge) { - gamedll_bridge_info info; - - info.engineFactory = (QueryValveInterface)engineFactory; - info.physicsFactory = (QueryValveInterface)physicsFactory; - info.fsFactory = (QueryValveInterface)fileSystemFactory; - info.pGlobals = pGlobals; - info.dllVersion = gamedll_version; - info.isgd = gamedll_iface; - info.gsFactory = gamedll_qvi; - info.vsp_listener_path = mm_path; + g_bridge_info.engineFactory = (QueryValveInterface)engineFactory; + g_bridge_info.physicsFactory = (QueryValveInterface)physicsFactory; + g_bridge_info.fsFactory = (QueryValveInterface)fileSystemFactory; + g_bridge_info.pGlobals = pGlobals; + g_bridge_info.dllVersion = gamedll_version; + g_bridge_info.isgd = gamedll_iface; + g_bridge_info.gsFactory = gamedll_qvi; + g_bridge_info.vsp_listener_path = mm_path; strcpy(error, "Unknown error"); - if (!gamedll_bridge->DLLInit_Pre(&info, error, sizeof(error))) + if (!gamedll_bridge->DLLInit_Pre(&g_bridge_info, error, sizeof(error))) { gamedll_bridge = NULL; mm_UnloadMetamodLibrary(); @@ -350,6 +566,8 @@ public: }; static IServerGameDLL isgd_thunk; +static ISource2Server is2s_thunk; +static ISource2ServerConfig is2sc_thunk; static void mm_PatchDllInit(bool patch) @@ -358,13 +576,27 @@ mm_PatchDllInit(bool patch) void **vtable_dest; SourceHook::MemFuncInfo mfp; - SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfp); + if (g_is_source2) + { + SourceHook::GetFuncInfo(&ISource2Server::Init, mfp); + } + else + { + SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfp); + } assert(mfp.isVirtual); assert(mfp.thisptroffs == 0); assert(mfp.vtbloffs == 0); - vtable_src = (void **)*(void **)&isgd_thunk; + if (g_is_source2) + { + vtable_src = (void **)*(void **)&is2s_thunk; + } + else + { + vtable_src = (void **)*(void **)&isgd_thunk; + } vtable_dest = (void **)*(void **)gamedll_iface; SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], @@ -393,12 +625,26 @@ mm_PatchDllShutdown() SourceHook::MemFuncInfo mfp; mfp.isVirtual = false; - SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfp); + if (g_is_source2) + { + SourceHook::GetFuncInfo(&ISource2Server::Shutdown, mfp); + } + else + { + SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfp); + } assert(mfp.isVirtual); assert(mfp.thisptroffs == 0); assert(mfp.vtbloffs == 0); - vtable_src = (void **)*(void **)&isgd_thunk; + if (g_is_source2) + { + vtable_src = (void **)*(void **)&is2s_thunk; + } + else + { + vtable_src = (void **)*(void **)&isgd_thunk; + } vtable_dest = (void **)*(void **)gamedll_iface; isgd_orig_shutdown = vtable_dest[isgd_shutdown_index]; @@ -406,20 +652,138 @@ mm_PatchDllShutdown() } static void -mm_PrepForGameLoad() +mm_PatchAllowDedicated(bool patch) { - mm_PatchDllInit(true); + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2ServerConfig::AllowDedicatedServers, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; + + SourceHook::SetMemAccess(&vtable_dest[is2sc_allowdedi_index], + sizeof(void*), + SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + if (patch) + { + assert(is2sc_orig_allowdedi == NULL); + is2sc_orig_allowdedi = vtable_dest[is2sc_allowdedi_index]; + vtable_dest[is2sc_allowdedi_index] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2sc_orig_allowdedi != NULL); + vtable_dest[is2sc_allowdedi_index] = is2sc_orig_allowdedi; + is2sc_orig_allowdedi = NULL; + } } +static void +mm_PatchConnect(bool patch) +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2ServerConfig::Connect, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; + + SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], + sizeof(void*), + SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + if (patch) + { + assert(is2sc_orig_connect == NULL); + is2sc_orig_connect = vtable_dest[mfp.vtblindex]; + vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2sc_orig_connect != NULL); + vtable_dest[mfp.vtblindex] = is2sc_orig_connect; + is2sc_orig_connect = NULL; + } +} + + void * mm_GameDllRequest(const char *name, int *ret) { - if (gamedll_lib != NULL && gamedll_bridge == NULL) + if (strncmp(name, "Source2ServerConfig", 19) == 0) { - return gamedll_qvi(name, ret); - } + g_is_source2 = true; + if (!mm_DetectGameInformation()) + { + if (ret != NULL) + *ret = 1; + return NULL; + } - if (strncmp(name, "ServerGameDLL", 13) == 0) + void *lib; + char error[255]; + void *ptr = NULL; + QueryValveInterface qvi; + for (unsigned int i = 0; i < gamedll_path_count; i++) + { + if (gamedll_libs[i] == NULL) + { + lib = mm_LoadLibrary(gamedll_paths[i], error, sizeof(error)); + if (lib == NULL) + continue; + gamedll_libs[i] = lib; + } + lib = gamedll_libs[i]; + qvi = (QueryValveInterface)mm_GetLibAddress(lib, "CreateInterface"); + if (qvi == NULL) + continue; + ptr = qvi(name, ret); + if (ptr != NULL) + { + gamedll_libs[i] = NULL; + break; + } + } + + if (ptr != NULL) + { + mm_FreeCachedLibraries(); + gamedll_lib = lib; + config_iface = (ISource2ServerConfig *) ptr; + gamedll_qvi = qvi; + + mm_PatchConnect(true); + mm_PatchAllowDedicated(true); + + if (ret != NULL) + *ret = 0; + return ptr; + } + } + else if (strncmp(name, "Source2Server0", 14) == 0) + { + gamedll_iface = (IServerGameDLL *)gamedll_qvi(name, ret); + gamedll_version = atoi(&name[13]); + mm_PatchDllInit(true); + + if (ret != NULL) + *ret = 0; + return gamedll_iface; + } + else if (strncmp(name, "ServerGameDLL", 13) == 0) { if (!mm_DetectGameInformation()) { @@ -460,13 +824,17 @@ mm_GameDllRequest(const char *name, int *ret) gamedll_iface = (IServerGameDLL *)ptr; gamedll_qvi = qvi; gamedll_version = atoi(&name[13]); - mm_PrepForGameLoad(); + mm_PatchDllInit(true); if (ret != NULL) *ret = 0; return ptr; } } + else if (gamedll_lib != NULL && gamedll_bridge == NULL) + { + return gamedll_qvi(name, ret); + } else if (game_info_detected == 0) { mm_LogFatal("Received interface request too early: %s", name); diff --git a/loader/loader.cpp b/loader/loader.cpp index f2a696b..906b913 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 sw=4 tw=99 noet : * ====================================================== * Metamod:Source - * Copyright (C) 2004-2010 AlliedModders LLC and authors. + * Copyright (C) 2004-2015 AlliedModders LLC and authors. * All rights reserved. * ====================================================== * @@ -90,6 +90,7 @@ static const char *backend_names[] = "2.insurgency", "2.contagion", "2.bms", + "2.source2" }; #if defined _WIN32 @@ -267,7 +268,9 @@ mm_GetGameName(char *buffer, size_t size) if (buffer[0] == 0) { - strncpy(buffer, ".", size); + // FIXME: this was "." and is now "dota" for Source2. + // That breaks Dark Messiah compatibility. + strncpy(buffer, "dota", size); } } diff --git a/loader/loader.h b/loader/loader.h index 9c11681..ef22666 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -2,7 +2,7 @@ * vim: set ts=4 sw=4 tw=99 noet : * ====================================================== * Metamod:Source - * Copyright (C) 2004-2009 AlliedModders LLC and authors. + * Copyright (C) 2004-2015 AlliedModders LLC and authors. * All rights reserved. * ====================================================== * @@ -102,6 +102,7 @@ enum MetamodBackend MMBackend_Insurgency, MMBackend_Contagion, MMBackend_BMS, + MMBackend_Source2, MMBackend_UNKNOWN }; diff --git a/public/loader_bridge.h b/loader/loader_bridge.h similarity index 100% rename from public/loader_bridge.h rename to loader/loader_bridge.h diff --git a/loader/utility.cpp b/loader/utility.cpp index 5de2716..c2af968 100644 --- a/loader/utility.cpp +++ b/loader/utility.cpp @@ -2,7 +2,7 @@ * vim: set ts=4 : * ====================================================== * Metamod:Source - * Copyright (C) 2004-2008 AlliedModders LLC and authors. + * Copyright (C) 2004-2015 AlliedModders LLC and authors. * All rights reserved. * ====================================================== * @@ -275,8 +275,14 @@ mm_PathCmp(const char *path1, const char *path2) } bool -mm_ResolvePath(const char *path, char *buffer, size_t maxlength) +mm_ResolvePath(const char *path, char *buffer, size_t maxlength, bool bSource2) { + char tmp[PLATFORM_MAX_PATH]; + if (bSource2) + { + mm_Format(tmp, sizeof(tmp), "../../%s", path); + path = tmp; + } #if defined _WIN32 return _fullpath(buffer, path, maxlength) != NULL; #elif defined __linux__ || defined __APPLE__ diff --git a/loader/utility.h b/loader/utility.h index c586d1b..25be3e6 100644 --- a/loader/utility.h +++ b/loader/utility.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ====================================================== * Metamod:Source - * Copyright (C) 2004-2008 AlliedModders LLC and authors. + * Copyright (C) 2004-2015 AlliedModders LLC and authors. * All rights reserved. * ====================================================== * @@ -43,7 +43,7 @@ extern void mm_UnloadLibrary(void *lib); extern bool -mm_ResolvePath(const char *path, char *buffer, size_t maxlength); +mm_ResolvePath(const char *path, char *buffer, size_t maxlength, bool bSource2); extern size_t mm_PathFormat(char *buffer, size_t len, const char *fmt, ...); diff --git a/loader2/AMBuilder b/loader2/AMBuilder deleted file mode 100644 index a40c986..0000000 --- a/loader2/AMBuilder +++ /dev/null @@ -1,20 +0,0 @@ -# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: -import os.path - -def configure_library(name, linux_defines): - binary = MMS.Library(builder, name) - binary.compiler.cxxincludes += [os.path.join(builder.sourcePath, 'core', 'sourcehook')] - binary.sources += [ - 'loader2.cpp', - 'gamedll.cpp', - #'serverplugin.cpp', - 'utility.cpp', - ] - - if builder.target_platform == 'linux': - binary.compiler.defines += linux_defines - - nodes = builder.Add(binary) - MMS.binaries += [nodes] - -configure_library('server', ['LIB_PREFIX="lib"', 'LIB_SUFFIX=".so"']) diff --git a/loader2/gamedll.cpp b/loader2/gamedll.cpp deleted file mode 100644 index c81e618..0000000 --- a/loader2/gamedll.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include -#include -#include -#include -#include -#include -#include "loader2.h" -#include -#include -#include "utility.h" -#include "gamedll.h" - -class ISource2Server; -class ISource2ServerConfig; - -#define MAX_GAMEDLL_PATHS 10 - -IGameDllBridge* gamedll_bridge = NULL; -static int game_info_detected = 0; -static char game_name[128]; -static char gamedll_paths[MAX_GAMEDLL_PATHS][PLATFORM_MAX_PATH]; -static void *gamedll_libs[MAX_GAMEDLL_PATHS]; -static unsigned int gamedll_path_count = 0; -static void *gamedll_lib = NULL; -static ISource2Server *gamedll_iface = NULL; -static ISource2ServerConfig *config_iface = NULL; -static QueryValveInterface gamedll_qvi = NULL; -static int gamedll_version = 0; -static int is2s_shutdown_index = -1; -static int is2sc_allowdedi_index = 20; -static char mm_path[PLATFORM_MAX_PATH]; - -#if defined _WIN32 -#define SERVER_NAME "server.dll" -#elif defined __APPLE__ -#define SERVER_NAME "server.dylib" -#elif defined __linux__ -#define SERVER_NAME "server" LIB_SUFFIX -#endif - -static bool mm_DetectGameInformation() -{ - char game_path[PLATFORM_MAX_PATH]; - - if (game_info_detected) - return game_info_detected == 1 ? true : false; - - game_info_detected = -1; - - mm_GetGameName(game_name, sizeof(game_name)); - - if (!mm_GetFileOfAddress((void*)mm_DetectGameInformation, mm_path, sizeof(mm_path))) - { - mm_LogFatal("Could not locate Metamod loader library path"); - return false; - } - - if (!mm_ResolvePath(game_name, game_path, sizeof(game_path))) - { - mm_LogFatal("Could not resolve path: %s", game_name); - return false; - } - - FILE *fp; - char gameinfo_path[PLATFORM_MAX_PATH]; - - mm_PathFormat(gameinfo_path, sizeof(gameinfo_path), "%s/gameinfo.gi", game_path); - if ((fp = fopen(gameinfo_path, "rt")) == NULL) - { - mm_LogFatal("Could not read file: %s", gameinfo_path); - return false; - } - - char temp_path[PLATFORM_MAX_PATH]; - char cur_path[PLATFORM_MAX_PATH]; - getcwd(cur_path, sizeof(cur_path)); - - char *ptr; - const char *lptr; - bool search = false; - char buffer[255], key[128], val[128]; - while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL) - { - mm_TrimComments(buffer); - mm_TrimLeft(buffer); - mm_TrimRight(buffer); - - if (stricmp(buffer, "SearchPaths") == 0) - search = true; - - if (!search) - continue; - - mm_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1); - if (stricmp(key, "Game") != 0 && stricmp(key, "GameBin") != 0) - continue; - - if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0) - { - ptr = &val[sizeof("|gameinfo_path|") - 1]; - if (ptr[0] == '.') - ptr++; - lptr = game_path; - } - else - { - ptr = val; - lptr = cur_path; - } - - if (stricmp(key, "GameBin") == 0) - mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../%s/" SERVER_NAME, lptr, ptr); - else if (!ptr[0]) - mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../bin/win32/" SERVER_NAME, lptr); - else - mm_PathFormat(temp_path, sizeof(temp_path), "%s/../../%s/bin/win32/" SERVER_NAME, lptr, ptr); - - if (mm_PathCmp(mm_path, temp_path)) - continue; - - FILE *exists = fopen(temp_path, "rb"); - if (!exists) - continue; - fclose(exists); - - /* exists is still non-NULL... use this as a flag */ - for (unsigned int i = 0; i < gamedll_path_count; i++) - { - if (mm_PathCmp(gamedll_paths[i], temp_path)) - { - exists = NULL; - break; - } - } - - if (!exists) - continue; - - mm_Format(gamedll_paths[gamedll_path_count], - PLATFORM_MAX_PATH, - "%s", - temp_path); - gamedll_path_count++; - - if (gamedll_path_count == MAX_GAMEDLL_PATHS) - break; - } - fclose(fp); - - game_info_detected = 1; - - if (gamedll_path_count == 0) - { - mm_LogFatal("Could not detect any valid game paths in gameinfo.gi"); - return false; - } - - return true; -} - -static void mm_FreeCachedLibraries() -{ - for (unsigned int i = 0; i < gamedll_path_count; i++) - { - if (gamedll_libs[i] == NULL) - continue; - mm_UnloadLibrary(gamedll_libs[i]); - } -} - -static void mm_PatchDllInit(bool patch); -static void mm_PatchDllShutdown(); -static void mm_PatchAllowDedicated(bool patch); -static void mm_PatchConnect(bool patch); - -static void *is2s_orig_init = NULL; -static void *is2s_orig_shutdown = NULL; -static void *is2sc_orig_allowdedi = NULL; -static void *is2sc_orig_connect = NULL; - -class VEmptyClass -{ -}; - -gamedll_bridge_info g_bridge_info; - -// Rough start order -// CreateInterfaceFn (IS2SC) - hook Connect and AllowDedicatedServer -// IS2SC::Connect - save factory pointer. return orig. remove hook. -// IS2SC::AllowDedicatedServer - return true. remove hook. -// CreateInterfaceFn (IS2S) - hook Init and Shutdown -// IS2S::Init - do same as old ISGD::DLLInit, including core load. return orig. remove hook. -// IS2S::Shutdown - <-- this - -enum InitReturnVal_t -{ - INIT_FAILED = 0, - INIT_OK, - - INIT_LAST_VAL, -}; - -class ISource2ServerConfig -{ -public: - virtual bool Connect(QueryValveInterface factory) - { - g_bridge_info.engineFactory = factory; - g_bridge_info.fsFactory = factory; - g_bridge_info.physicsFactory = factory; - - - /* Call the original */ - bool result; - { - union - { - bool(VEmptyClass::*mfpnew)(QueryValveInterface factory); -#if defined _WIN32 - void *addr; - } u; - u.addr = is2sc_orig_connect; -#else - struct - { - void *addr; - intptr_t adjustor; - } s; - } u; - u.s.addr = is2sc_orig_connect; - u.s.adjustor = 0; -#endif - result = (((VEmptyClass *) config_iface)->*u.mfpnew)(factory); - } - - mm_PatchConnect(false); - - return result; - } - virtual bool AllowDedicatedServers(int universe) const - { - mm_PatchAllowDedicated(false); - return true; - } -}; - -class ISource2Server -{ -public: - virtual bool Connect(QueryValveInterface factory) { return true; } - virtual void Disconnect() {} - virtual void *QueryInterface(const char *pInterfaceName) { return nullptr; } - - virtual InitReturnVal_t Init() - { - char error[255]; - if (mm_backend == MMBackend_UNKNOWN) - { - mm_LogFatal("Could not detect engine version"); - } - else - { - if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) - { - mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); - } - else - { - typedef IGameDllBridge *(*GetGameDllBridge)(); - GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); - if (get_bridge == NULL) - { - mm_UnloadMetamodLibrary(); - mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); - } - else - { - gamedll_bridge = get_bridge(); - } - } - } - - if (gamedll_bridge) - { - g_bridge_info.pGlobals = nullptr;// pGlobals; - g_bridge_info.dllVersion = gamedll_version; - g_bridge_info.isgd = gamedll_iface; - g_bridge_info.gsFactory = gamedll_qvi; - g_bridge_info.vsp_listener_path = mm_path; - - strcpy(error, "Unknown error"); - if (!gamedll_bridge->DLLInit_Pre(&g_bridge_info, error, sizeof(error))) - { - gamedll_bridge = NULL; - mm_UnloadMetamodLibrary(); - mm_LogFatal("Unknown error loading Metamod for engine %d: %s", mm_backend, error); - } - } - - /* Call the original */ - InitReturnVal_t result; - { - union - { - InitReturnVal_t(VEmptyClass::*mfpnew)(); -#if defined _WIN32 - void *addr; - } u; - u.addr = is2s_orig_init; -#else - struct - { - void *addr; - intptr_t adjustor; - } s; - } u; - u.s.addr = is2s_orig_init; - u.s.adjustor = 0; -#endif - result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); - } - - /** - * :TODO: possible logic hole here, what happens if the gamedll REALLY returns false? - * I'm pretty sure we'll die horribly. - */ - - if (!result) - { - gamedll_bridge->Unload(); - mm_UnloadMetamodLibrary(); - gamedll_bridge = NULL; - } - else if (gamedll_bridge != NULL) - { - gamedll_bridge->DLLInit_Post(&is2s_shutdown_index); - assert(is2s_shutdown_index != -1); - mm_PatchDllShutdown(); - } - - mm_PatchDllInit(false); - - return result; - } - - virtual void Shutdown() - { - gamedll_bridge->Unload(); - gamedll_bridge = NULL; - mm_UnloadMetamodLibrary(); - - /* Call original function */ - { - union - { - void (VEmptyClass::*mfpnew)(); -#if defined _WIN32 - void *addr; - } u; - u.addr = is2s_orig_shutdown; -#else - struct - { - void *addr; - intptr_t adjustor; - } s; - } u; - u.s.addr = is2s_orig_shutdown; - u.s.adjustor = 0; -#endif - (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(); - } - - mm_UnloadLibrary(gamedll_lib); - gamedll_lib = NULL; - } -}; - -static ISource2Server is2s_thunk; -static ISource2ServerConfig is2sc_thunk; - -static void mm_PatchDllInit(bool patch) -{ - void **vtable_src; - void **vtable_dest; - SourceHook::MemFuncInfo mfp; - - SourceHook::GetFuncInfo(&ISource2Server::Init, mfp); - - assert(mfp.isVirtual); - assert(mfp.thisptroffs == 0); - assert(mfp.vtbloffs == 0); - - vtable_src = (void **)*(void **)&is2s_thunk; - vtable_dest = (void **)*(void **)gamedll_iface; - - SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], - sizeof(void*), - SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); - - if (patch) - { - assert(is2s_orig_init == NULL); - is2s_orig_init = vtable_dest[mfp.vtblindex]; - vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; - } - else - { - assert(is2s_orig_init != NULL); - vtable_dest[mfp.vtblindex] = is2s_orig_init; - is2s_orig_init = NULL; - } -} - -static void mm_PatchDllShutdown() -{ - void **vtable_src; - void **vtable_dest; - SourceHook::MemFuncInfo mfp; - - mfp.isVirtual = false; - SourceHook::GetFuncInfo(&ISource2Server::Shutdown, mfp); - assert(mfp.isVirtual); - assert(mfp.thisptroffs == 0); - assert(mfp.vtbloffs == 0); - - vtable_src = (void **)*(void **)&is2s_thunk; - vtable_dest = (void **)*(void **)gamedll_iface; - - is2s_orig_shutdown = vtable_dest[is2s_shutdown_index]; - vtable_dest[is2s_shutdown_index] = vtable_src[mfp.vtblindex]; -} - -static void mm_PatchAllowDedicated(bool patch) -{ - void **vtable_src; - void **vtable_dest; - SourceHook::MemFuncInfo mfp; - - SourceHook::GetFuncInfo(&ISource2ServerConfig::AllowDedicatedServers, mfp); - - assert(mfp.isVirtual); - assert(mfp.thisptroffs == 0); - assert(mfp.vtbloffs == 0); - - vtable_src = (void **) *(void **) &is2sc_thunk; - vtable_dest = (void **) *(void **) config_iface; - - SourceHook::SetMemAccess(&vtable_dest[is2sc_allowdedi_index], - sizeof(void*), - SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); - - if (patch) - { - assert(is2sc_orig_allowdedi == NULL); - is2sc_orig_allowdedi = vtable_dest[is2sc_allowdedi_index]; - vtable_dest[is2sc_allowdedi_index] = vtable_src[mfp.vtblindex]; - } - else - { - assert(is2sc_orig_allowdedi != NULL); - vtable_dest[is2sc_allowdedi_index] = is2sc_orig_allowdedi; - is2sc_orig_allowdedi = NULL; - } -} - -static void mm_PatchConnect(bool patch) -{ - void **vtable_src; - void **vtable_dest; - SourceHook::MemFuncInfo mfp; - - SourceHook::GetFuncInfo(&ISource2ServerConfig::Connect, mfp); - - assert(mfp.isVirtual); - assert(mfp.thisptroffs == 0); - assert(mfp.vtbloffs == 0); - - vtable_src = (void **) *(void **) &is2sc_thunk; - vtable_dest = (void **) *(void **) config_iface; - - SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], - sizeof(void*), - SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); - - if (patch) - { - assert(is2sc_orig_connect == NULL); - is2sc_orig_connect = vtable_dest[mfp.vtblindex]; - vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; - } - else - { - assert(is2sc_orig_connect != NULL); - vtable_dest[mfp.vtblindex] = is2sc_orig_connect; - is2sc_orig_connect = NULL; - } -} - -enum ServerIface -{ - Other, - ServerConfig, - Server -}; - -void * -mm_GameDllRequest(const char *name, int *ret) -{ - if (strncmp(name, "Source2ServerConfig", 19) == 0) - { - if (!mm_DetectGameInformation()) - { - if (ret != NULL) - *ret = 1; - return NULL; - } - - void *lib; - char error[255]; - void *ptr = NULL; - QueryValveInterface qvi; - for (unsigned int i = 0; i < gamedll_path_count; i++) - { - if (gamedll_libs[i] == NULL) - { - lib = mm_LoadLibrary(gamedll_paths[i], error, sizeof(error)); - if (lib == NULL) - continue; - gamedll_libs[i] = lib; - } - lib = gamedll_libs[i]; - qvi = (QueryValveInterface)mm_GetLibAddress(lib, "CreateInterface"); - if (qvi == NULL) - continue; - ptr = qvi(name, ret); - if (ptr != NULL) - { - gamedll_libs[i] = NULL; - break; - } - } - - if (ptr != NULL) - { - mm_FreeCachedLibraries(); - gamedll_lib = lib; - config_iface = (ISource2ServerConfig *) ptr; - gamedll_qvi = qvi; - - mm_PatchConnect(true); - mm_PatchAllowDedicated(true); - - if (ret != NULL) - *ret = 0; - return ptr; - } - } - else if (strncmp(name, "Source2Server0", 14) == 0) - { - gamedll_iface = (ISource2Server *)gamedll_qvi(name, ret); - gamedll_version = atoi(&name[13]); - mm_PatchDllInit(true); - - if (ret != NULL) - *ret = 0; - return gamedll_iface; - } - else if (gamedll_lib != NULL && gamedll_bridge == NULL) - { - return gamedll_qvi(name, ret); - } - else if (game_info_detected == 0) - { - mm_LogFatal("Received interface request too early: %s", name); - } - - if (ret != NULL) - *ret = 1; - return NULL; -} - diff --git a/loader2/gamedll.h b/loader2/gamedll.h deleted file mode 100644 index 1248ef8..0000000 --- a/loader2/gamedll.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * vim: set ts=4 : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ -#define _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ - -#include "loader_bridge.h" - -extern void * -mm_GameDllRequest(const char *name, int *ret); - -extern IGameDllBridge* gamedll_bridge; - -#endif /* _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ */ - diff --git a/loader2/loader2.cpp b/loader2/loader2.cpp deleted file mode 100644 index e177f38..0000000 --- a/loader2/loader2.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#include -#include -#include -#include -#include -#include -#include "loader2.h" -#include "gamedll.h" -#include "utility.h" -#if defined __APPLE__ -#include -#endif - -static HMODULE mm_library = NULL; -static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log"; -MetamodBackend mm_backend = MMBackend_Source2; - -extern void -mm_LogFatal(const char *message, ...) -{ - FILE *fp; - time_t t; - va_list ap; - char header[256]; - - fp = fopen(mm_fatal_logfile, "at"); - if (!fp && (fp = fopen("metamod-fatal.log", "at")) == NULL) - return; - - t = time(NULL); - strftime(header, sizeof(header), "%m/%d/%Y - %H:%M:%S", localtime(&t)); - fprintf(fp, "L %s: ", header); - - va_start(ap, message); - vfprintf(fp, message, ap); - va_end(ap); - - fprintf(fp, "\n"); - - fclose(fp); -} - -#if defined _WIN32 -#define LIBRARY_EXT ".dll" -#define LIBRARY_MINEXT ".dll" -#elif defined __APPLE__ -#define LIBRARY_EXT ".dylib" -#define LIBRARY_MINEXT ".dylib" -#elif defined __linux__ -#define LIBRARY_EXT LIB_SUFFIX -#define LIBRARY_MINEXT ".so" -#endif - -bool -mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength) -{ - size_t len, temp_len; - char mm_path[PLATFORM_MAX_PATH * 2]; - - /* Get our path */ - if (!mm_GetFileOfAddress((void*)mm_GetFileOfAddress, mm_path, sizeof(mm_path))) - return false; - - len = strlen(mm_path); - temp_len = strlen("server" LIBRARY_EXT); - if (len < temp_len) - return false; - - /* Build log file name */ - mm_path[len - temp_len] = '\0'; - mm_Format(mm_fatal_logfile, - sizeof(mm_fatal_logfile), - "%smetamod-fatal.log", - mm_path); - - /* Replace server2.dll with the new binary we want */ - mm_Format(&mm_path[len - temp_len], - sizeof(mm_path) - (len - temp_len), - "metamod.2.s2" LIBRARY_MINEXT); - - mm_library = (HMODULE)mm_LoadLibrary(mm_path, buffer, maxlength); - - return (mm_library != NULL); -} - -void -mm_UnloadMetamodLibrary() -{ - mm_UnloadLibrary(mm_library); - mm_library = NULL; -} - -#if defined _WIN32 -#define EXPORT extern "C" __declspec(dllexport) -#elif defined __GNUC__ -#if __GNUC__ == 4 -#define EXPORT extern "C" __attribute__ ((visibility("default"))) -#else -#define EXPORT extern "C" -#endif -#endif - -EXPORT void * -CreateInterface(const char *name, int *ret) -{ - void *ptr; - if (gamedll_bridge == NULL) - { - /* Load as gamedll */ - ptr = mm_GameDllRequest(name, ret); - } - else - { - /* If we've got a gamedll bridge, forward the request. */ - return gamedll_bridge->QueryInterface(name, ret); - } - - if (ret != NULL) - *ret = (ptr != NULL) ? 0 : 1; - - return ptr; -} - -void * -mm_GetProcAddress(const char *name) -{ - return mm_GetLibAddress(mm_library, name); -} - -void -mm_GetGameName(char *buffer, size_t size) -{ - buffer[0] = '\0'; - -#if defined _WIN32 - static char game[128]; - - LPWSTR pCmdLine = GetCommandLineW(); - int argc; - LPWSTR *wargv = CommandLineToArgvW(pCmdLine, &argc); - for (int i = 0; i < argc; ++i) - { - if (wcscmp(wargv[i], L"-game") != 0) - continue; - - if (++i >= argc) - break; - - wcstombs(buffer, wargv[i], size); - buffer[size-1] = '\0'; - break; - } - - LocalFree(wargv); - -#elif defined __APPLE__ - int argc = *_NSGetArgc(); - char **argv = *_NSGetArgv(); - for (int i = 0; i < argc; ++i) - { - if (strcmp(argv[i], "-game") != 0) - continue; - - if (++i >= argc) - break; - - strncpy(buffer, argv[i], size); - buffer[size-1] = '\0'; - break; - } - -#elif defined __linux__ - FILE *pFile = fopen("/proc/self/cmdline", "rb"); - if (pFile) - { - char *arg = NULL; - size_t argsize = 0; - bool bNextIsGame = false; - - while (getdelim(&arg, &argsize, 0, pFile) != -1) - { - if (bNextIsGame) - { - strncpy(buffer, arg, size); - buffer[size-1] = '\0'; - break; - } - - if (strcmp(arg, "-game") == 0) - { - bNextIsGame = true; - } - } - - free(arg); - fclose(pFile); - } -#else -#error unsupported platform -#endif - - if (buffer[0] == 0) - { - strncpy(buffer, "dota", size); - } -} - diff --git a/loader2/loader2.h b/loader2/loader2.h deleted file mode 100644 index ea16fb9..0000000 --- a/loader2/loader2.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_H_ -#define _INCLUDE_METAMOD_SOURCE_LOADER_H_ - -// System -#define SH_SYS_WIN32 1 -#define SH_SYS_LINUX 2 -#define SH_SYS_APPLE 3 - -// Platform -#define SH_XP_POSIX 10 -#define SH_XP_WINAPI 20 - -// Compiler -#define SH_COMP_GCC 1 -#define SH_COMP_MSVC 2 - -#if defined WIN32 -#define SH_SYS SH_SYS_WIN32 -#define SH_XP SH_XP_WINAPI -#define SH_COMP SH_COMP_MSVC -#define WINDOWS_LEAN_AND_MEAN -#include -#include -#define PLATFORM_MAX_PATH MAX_PATH -#define PATH_SEP_STR "\\" -#define PATH_SEP_CHAR '\\' -#define ALT_SEP_CHAR '/' -#elif defined __linux__ || defined __APPLE__ -#if defined __linux__ -#define SH_SYS SH_SYS_LINUX -#elif defined __APPLE__ -#define SH_SYS SH_SYS_APPLE -#endif -#define SH_XP SH_XP_POSIX -#define SH_COMP SH_COMP_GCC -#include -#include -#include -#include -#if SH_SYS == SH_SYS_APPLE -#include -#endif -typedef void * HMODULE; -#define PLATFORM_MAX_PATH PATH_MAX -#define PATH_SEP_STR "/" -#define PATH_SEP_CHAR '/' -#define ALT_SEP_CHAR '\\' -#else -#error "OS detection failed" -#endif - -#include -#include "loader_bridge.h" - -#define SH_PTRSIZE sizeof(void*) - -extern bool -mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength); - -extern void * -mm_GetProcAddress(const char *name); - -extern void -mm_UnloadMetamodLibrary(); - -extern void -mm_LogFatal(const char *message, ...); - -extern void -mm_GetGameName(char *buffer, size_t size); - -extern MetamodBackend mm_backend; - -#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_H_ */ - diff --git a/loader2/utility.cpp b/loader2/utility.cpp deleted file mode 100644 index ce75c5c..0000000 --- a/loader2/utility.cpp +++ /dev/null @@ -1,546 +0,0 @@ -/** - * vim: set ts=4 : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Version: $Id$ - */ - -#include -#include -#include -#include -#include -#include -#include "loader2.h" -#include "utility.h" - -#if defined __linux__ -#include - -#define PAGE_SIZE 4096 -#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) -#elif defined __APPLE__ -#include -#endif - -#if defined _WIN32 -static void -mm_GetPlatformError(char *buffer, size_t maxlength) -{ - DWORD dw = GetLastError(); - FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)buffer, - maxlength, - NULL); -} -#endif - - -size_t -mm_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params) -{ - size_t len = vsnprintf(buffer, maxlength, fmt, params); - - if (len >= maxlength) - { - len = maxlength - 1; - buffer[len] = '\0'; - } - - return len; -} - -size_t -mm_Format(char *buffer, size_t maxlength, const char *fmt, ...) -{ - size_t len; - va_list ap; - - va_start(ap, fmt); - len = mm_FormatArgs(buffer, maxlength, fmt, ap); - va_end(ap); - - return len; -} - -size_t -mm_PathFormat(char *buffer, size_t maxlen, const char *fmt, ...) -{ - size_t len; - va_list ap; - - va_start(ap, fmt); - len = mm_FormatArgs(buffer, maxlen, fmt, ap); - va_end(ap); - - for (size_t i = 0; i < len; i++) - { - if (buffer[i] == ALT_SEP_CHAR) - buffer[i] = PATH_SEP_CHAR; - } - - return len; -} - -void -mm_TrimLeft(char *buffer) -{ - /* Let's think of this as our iterator */ - char *i = buffer; - - /* Make sure the buffer isn't null */ - if (i && *i) - { - /* Add up number of whitespace characters */ - while(isspace((unsigned char) *i)) - i++; - - /* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */ - if (i != buffer) - memmove(buffer, i, (strlen(i) + 1) * sizeof(char)); - } -} - -void -mm_TrimRight(char *buffer) -{ - /* Make sure buffer isn't null */ - if (buffer) - { - size_t len = strlen(buffer); - - /* Loop through buffer backwards while replacing whitespace chars with null chars */ - for (size_t i = len - 1; i < len; i--) - { - if (isspace((unsigned char) buffer[i])) - buffer[i] = '\0'; - else - break; - } - } -} - -/* :TODO: this should skip string literals */ -void -mm_TrimComments(char *buffer) -{ - int num_sc = 0; - size_t len = strlen(buffer); - if (buffer) - { - for (int i = len - 1; i >= 0; i--) - { - if (buffer[i] == '/') - { - if (++num_sc >= 2 && i==0) - { - buffer[i] = '\0'; - return; - } - } - else - { - if (num_sc >= 2) - { - buffer[i] = '\0'; - return; - } - num_sc = 0; - } - /* size_t won't go below 0, manually break out */ - if (i == 0) - break; - - } - } -} - -void -mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2) -{ - size_t start; - size_t len = strlen(str); - - for (start = 0; start < len; start++) - { - if (!isspace(str[start])) - break; - } - - size_t end; - for (end = start; end < len; end++) - { - if (isspace(str[end])) - break; - } - - size_t i, c = 0; - for (i = start; i < end; i++, c++) - { - if (c >= len1) - break; - buf1[c] = str[i]; - } - buf1[c] = '\0'; - - for (start = end; start < len; start++) - { - if (!isspace(str[start])) - break; - } - - for (c = 0; start < len; start++, c++) - { - if (c >= len2) - break; - buf2[c] = str[start]; - } - buf2[c] = '\0'; -} - -bool -mm_PathCmp(const char *path1, const char *path2) -{ - size_t pos1 = 0, pos2 = 0; - - while (true) - { - if (path1[pos1] == '\0' || path2[pos2] == '\0') - return (path1[pos1] == path2[pos2]); - - if (path1[pos1] == PATH_SEP_CHAR) - { - if (path2[pos2] != PATH_SEP_CHAR) - return false; - - /* Look for extra path chars */ - while (path1[++pos1]) - { - if (path1[pos1] != PATH_SEP_CHAR) - break; - } - while (path2[++pos2]) - { - if (path2[pos2] != PATH_SEP_CHAR) - break; - } - continue; - } - - /* If we're at a different non-alphanumeric, the next character MUST match */ - if ((((unsigned)path1[pos1] & 0x80) && path1[pos1] != path2[pos2]) - || - (!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2])) - ) - { - return false; - } - - #ifdef WIN32 - if (toupper(path1[pos1]) != toupper(path2[pos2])) - #else - if (path1[pos1] != path2[pos2]) - #endif - { - return false; - } - - pos1++; - pos2++; - } -} - -bool -mm_ResolvePath(const char *path, char *buffer, size_t maxlength) -{ - char tmp[PLATFORM_MAX_PATH]; - mm_Format(tmp, sizeof(tmp), "../../%s", path); -#if defined _WIN32 - return _fullpath(buffer, tmp, maxlength) != NULL; -#elif defined __linux__ || defined __APPLE__ - assert(maxlength >= PATH_MAX); - return realpath(tmp, buffer) != NULL; -#endif -} - -void * -mm_LoadLibrary(const char *path, char *buffer, size_t maxlength) -{ - void *lib; - -#if defined _WIN32 - lib = (void*)LoadLibrary(path); - - if (lib == NULL) - { - mm_GetPlatformError(buffer, maxlength); - return NULL; - } -#elif defined __linux__ || defined __APPLE__ - lib = dlopen(path, RTLD_NOW); - - if (lib == NULL) - { - mm_Format(buffer, maxlength, "%s", dlerror()); - return NULL; - } -#endif - - return lib; -} - -void * -mm_GetLibAddress(void *lib, const char *name) -{ -#if defined _WIN32 - return GetProcAddress((HMODULE)lib, name); -#elif defined __linux__ || defined __APPLE__ - return dlsym(lib, name); -#endif -} - -void -mm_UnloadLibrary(void *lib) -{ -#if defined _WIN32 - FreeLibrary((HMODULE)lib); -#elif defined __linux__ || defined __APPLE__ - dlclose(lib); -#endif -} - -bool -mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength) -{ -#if defined _WIN32 - MEMORY_BASIC_INFORMATION mem; - if (!VirtualQuery(pAddr, &mem, sizeof(mem))) - return false; - if (mem.AllocationBase == NULL) - return false; - HMODULE dll = (HMODULE)mem.AllocationBase; - GetModuleFileName(dll, (LPTSTR)buffer, maxlength); -#elif defined __linux__ || defined __APPLE__ - Dl_info info; - if (!dladdr(pAddr, &info)) - return false; - if (!info.dli_fbase || !info.dli_fname) - return false; - const char *dllpath = info.dli_fname; - snprintf(buffer, maxlength, "%s", dllpath); -#endif - return true; -} - -struct DynLibInfo -{ - void *baseAddress; - size_t memorySize; -}; - -static bool -mm_GetLibraryInfo(const void *libPtr, DynLibInfo &lib) -{ - uintptr_t baseAddr; - - if (libPtr == NULL) - { - return false; - } - -#ifdef _WIN32 - - MEMORY_BASIC_INFORMATION info; - IMAGE_DOS_HEADER *dos; - IMAGE_NT_HEADERS *pe; - IMAGE_FILE_HEADER *file; - IMAGE_OPTIONAL_HEADER *opt; - - if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) - { - return false; - } - - baseAddr = reinterpret_cast(info.AllocationBase); - - /* All this is for our insane sanity checks :o */ - dos = reinterpret_cast(baseAddr); - pe = reinterpret_cast(baseAddr + dos->e_lfanew); - file = &pe->FileHeader; - opt = &pe->OptionalHeader; - - /* Check PE magic and signature */ - if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - return false; - } - - /* Check architecture, which is 32-bit/x86 right now - * Should change this for 64-bit if Valve gets their act together - */ - if (file->Machine != IMAGE_FILE_MACHINE_I386) - { - return false; - } - - /* For our purposes, this must be a dynamic library */ - if ((file->Characteristics & IMAGE_FILE_DLL) == 0) - { - return false; - } - - /* Finally, we can do this */ - lib.memorySize = opt->SizeOfImage; - -#elif defined __linux__ - - Dl_info info; - Elf32_Ehdr *file; - Elf32_Phdr *phdr; - uint16_t phdrCount; - - if (!dladdr(libPtr, &info)) - { - return false; - } - - if (!info.dli_fbase || !info.dli_fname) - { - return false; - } - - /* This is for our insane sanity checks :o */ - baseAddr = reinterpret_cast(info.dli_fbase); - file = reinterpret_cast(baseAddr); - - /* Check ELF magic */ - if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) - { - return false; - } - - /* Check ELF version */ - if (file->e_ident[EI_VERSION] != EV_CURRENT) - { - return false; - } - - /* Check ELF architecture, which is 32-bit/x86 right now - * Should change this for 64-bit if Valve gets their act together - */ - if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB) - { - return false; - } - - /* For our purposes, this must be a dynamic library/shared object */ - if (file->e_type != ET_DYN) - { - return false; - } - - phdrCount = file->e_phnum; - phdr = reinterpret_cast(baseAddr + file->e_phoff); - - for (uint16_t i = 0; i < phdrCount; i++) - { - Elf32_Phdr &hdr = phdr[i]; - - /* We only really care about the segment with executable code */ - if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R)) - { - /* From glibc, elf/dl-load.c: - * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) - * & ~(GLRO(dl_pagesize) - 1)); - * - * In glibc, the segment file size is aligned up to the nearest page size and - * added to the virtual address of the segment. We just want the size here. - */ - lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz); - break; - } - } - -#elif defined __APPLE__ - - Dl_info info; - struct mach_header *file; - struct segment_command *seg; - uint32_t cmd_count; - - if (!dladdr(libPtr, &info)) - { - return false; - } - - if (!info.dli_fbase || !info.dli_fname) - { - return false; - } - - /* This is for our insane sanity checks :o */ - baseAddr = (uintptr_t)info.dli_fbase; - file = (struct mach_header *)baseAddr; - - /* Check Mach-O magic */ - if (file->magic != MH_MAGIC) - { - return false; - } - - /* Check architecture (32-bit/x86) */ - if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL) - { - return false; - } - - /* For our purposes, this must be a dynamic library */ - if (file->filetype != MH_DYLIB) - { - return false; - } - - cmd_count = file->ncmds; - seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header)); - - /* Add up memory sizes of mapped segments */ - for (uint32_t i = 0; i < cmd_count; i++) - { - if (seg->cmd == LC_SEGMENT) - { - lib.memorySize += seg->vmsize; - } - - seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize); - } - -#endif - - lib.baseAddress = reinterpret_cast(baseAddr); - - return true; -} diff --git a/loader2/utility.h b/loader2/utility.h deleted file mode 100644 index 9d8b40a..0000000 --- a/loader2/utility.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * vim: set ts=4 : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2015 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ -#define _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ - -#include - -extern size_t -mm_Format(char *buffer, size_t maxlength, const char *fmt, ...); - -extern void * -mm_LoadLibrary(const char *path, char *buffer, size_t maxlength); - -extern void * -mm_GetLibAddress(void *lib, const char *name); - -extern void -mm_UnloadLibrary(void *lib); - -extern bool -mm_ResolvePath(const char *path, char *buffer, size_t maxlength); - -extern size_t -mm_PathFormat(char *buffer, size_t len, const char *fmt, ...); - -extern void -mm_TrimLeft(char *buffer); - -extern void -mm_TrimRight(char *buffer); - -extern void -mm_TrimComments(char *buffer); - -extern void -mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2); - -extern bool -mm_PathCmp(const char *path1, const char *path2); - -extern bool -mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength); - -#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ */ - diff --git a/public/loader_public.h b/public/loader_public.h deleted file mode 100644 index 18c8536..0000000 --- a/public/loader_public.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ====================================================== - * Metamod:Source - * Copyright (C) 2004-2010 AlliedModders LLC and authors. - * All rights reserved. - * ====================================================== - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef _INCLUDE_METAMOD_LOADER_PUBLIC_H_ -#define _INCLUDE_METAMOD_LOADER_PUBLIC_H_ - -enum MetamodBackend -{ - MMBackend_Episode1 = 0, - MMBackend_DarkMessiah, - MMBackend_Episode2, - MMBackend_BloodyGoodTime, - MMBackend_EYE, - MMBackend_CSS, - MMBackend_Episode2Valve_OBSOLETE, - MMBackend_Left4Dead, - MMBackend_Left4Dead2, - MMBackend_AlienSwarm, - MMBackend_Portal2, - MMBackend_CSGO, - MMBackend_DOTA, - MMBackend_HL2DM, - MMBackend_DODS, - MMBackend_TF2, - MMBackend_NuclearDawn, - MMBackend_SDK2013, - MMBackend_Blade, - MMBackend_Insurgency, - MMBackend_Contagion, - MMBackend_BMS, - MMBackend_Source2, - - MMBackend_UNKNOWN -}; - -#endif // _INCLUDE_METAMOD_LOADER_PUBLIC_H_ \ No newline at end of file From f65b6c985629a397b2fa59e299465ebc9f286dcb Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 9 Jul 2015 14:27:18 -0400 Subject: [PATCH 05/44] Fix core load on s2. --- AMBuildScript | 2 +- loader/gamedll.cpp | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index d207c37..efa4b3f 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -38,7 +38,7 @@ PossibleSDKs = { 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), - 'source2': SDK('HL2SDKSOURCE2', '2.s2', '22', 'SOURCE2', WinOnly, 'source2'), + 'source2': SDK('HL2SDKSOURCE2', '2.source2', '22', 'SOURCE2', WinOnly, 'source2'), } def ResolveEnvPath(env, folder): diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 000f900..e04a669 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -300,30 +300,25 @@ public: virtual InitReturnVal_t Init() { + mm_backend = MMBackend_Source2; + char error[255]; - if (mm_backend == MMBackend_UNKNOWN) + if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) { - mm_LogFatal("Could not detect engine version"); + mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); } else { - if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) + typedef IGameDllBridge *(*GetGameDllBridge)(); + GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); + if (get_bridge == NULL) { - mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); + mm_UnloadMetamodLibrary(); + mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); } else { - typedef IGameDllBridge *(*GetGameDllBridge)(); - GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); - if (get_bridge == NULL) - { - mm_UnloadMetamodLibrary(); - mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); - } - else - { - gamedll_bridge = get_bridge(); - } + gamedll_bridge = get_bridge(); } } From 1f1aca02f39d77f984cdfb24527edd9c3afdfb93 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 9 Jul 2015 14:24:18 -0500 Subject: [PATCH 06/44] Fix build of SourceHook tests --- core/sourcehook/test/main.cpp | 7 +- core/sourcehook/test/msvc12/test.sln | 28 ++ core/sourcehook/test/msvc12/test.vcxproj | 272 ++++++++++++++++++ .../test/msvc12/test.vcxproj.filters | 191 ++++++++++++ 4 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 core/sourcehook/test/msvc12/test.sln create mode 100644 core/sourcehook/test/msvc12/test.vcxproj create mode 100644 core/sourcehook/test/msvc12/test.vcxproj.filters diff --git a/core/sourcehook/test/main.cpp b/core/sourcehook/test/main.cpp index dc1fb88..77a32f2 100644 --- a/core/sourcehook/test/main.cpp +++ b/core/sourcehook/test/main.cpp @@ -18,6 +18,11 @@ using namespace std; bool g_Verbose; +struct Unloader : public SourceHook::Impl::UnloadListener +{ + void ReadyToUnload(SourceHook::Plugin) { } +} g_UnloadListener; + #define DECL_TEST(x) bool Test##x(std::string &error); #define DO_TEST(x) \ @@ -102,7 +107,7 @@ void Test_CompleteShutdown(SourceHook::ISourceHook *shptr) void Test_UnloadPlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug) { - static_cast(shptr)->UnloadPlugin(plug); + static_cast(shptr)->UnloadPlugin(plug, &g_UnloadListener); } void Test_PausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug) diff --git a/core/sourcehook/test/msvc12/test.sln b/core/sourcehook/test/msvc12/test.sln new file mode 100644 index 0000000..e69e650 --- /dev/null +++ b/core/sourcehook/test/msvc12/test.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{456BBA64-FF14-4292-8443-3BA79E4D84CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_NoDebugRuntimeLib|Win32 = Debug_NoDebugRuntimeLib|Win32 + Debug|Win32 = Debug|Win32 + DebugOpt|Win32 = DebugOpt|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.ActiveCfg = Debug_NoDebugRuntimeLib|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.Build.0 = Debug_NoDebugRuntimeLib|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.Build.0 = Debug|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.ActiveCfg = DebugOpt|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.Build.0 = DebugOpt|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.ActiveCfg = Release|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/core/sourcehook/test/msvc12/test.vcxproj b/core/sourcehook/test/msvc12/test.vcxproj new file mode 100644 index 0000000..cb22fcd --- /dev/null +++ b/core/sourcehook/test/msvc12/test.vcxproj @@ -0,0 +1,272 @@ + + + + + DebugOpt + Win32 + + + Debug_NoDebugRuntimeLib + Win32 + + + Debug + Win32 + + + Release + Win32 + + + + {456BBA64-FF14-4292-8443-3BA79E4D84CC} + test + Win32Proj + + + + Application + v120 + MultiByte + + + Application + v120 + MultiByte + + + Application + v120 + MultiByte + + + Application + v120 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + Debug\ + Debug\ + true + + + Release\ + Release\ + false + + + DebugOpt\ + DebugOpt\ + true + + + Debug_NoDebugRuntimeLib\ + Debug_NoDebugRuntimeLib\ + true + + + + Disabled + Neither + ../..;..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;SH_DEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + true + EnableFastChecks + MultiThreadedDebug + true + true + + Level3 + EditAndContinue + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + MachineX86 + + + + + Full + OnlyExplicitInline + Size + true + ../..;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + + + Level3 + true + ProgramDatabase + + + $(OutDir)test.exe + true + true + true + Console + true + true + false + + MachineX86 + + + + + Full + OnlyExplicitInline + false + Size + true + ..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + Default + MultiThreaded + true + true + + Level3 + ProgramDatabase + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + MachineX86 + + + + + Disabled + Neither + ../..;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + true + Sync + EnableFastChecks + MultiThreaded + true + true + + Level3 + EditAndContinue + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + MachineX86 + + + + + + + + + + + + + + + + + + + + false + false + + + + + + + + + + + + + + echo on +pushd ..\..\generate +shworker.exe iter sourcehook.hxx sourcehook.h 16 +copy sourcehook.h ..\sourcehook.h +popd + + ..\..\sourcehook.h;%(Outputs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/sourcehook/test/msvc12/test.vcxproj.filters b/core/sourcehook/test/msvc12/test.vcxproj.filters new file mode 100644 index 0000000..74a54b8 --- /dev/null +++ b/core/sourcehook/test/msvc12/test.vcxproj.filters @@ -0,0 +1,191 @@ + + + + + {097d3bc9-e1f2-4054-93f3-b12d28409a01} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c1c8bd55-c7ae-46fc-a115-e490b5068b5c} + + + {17326c78-c7e4-456b-b9df-019e07ca478f} + + + {c15408a4-1aa9-485e-916b-c4eeaddeeee2} + h;hpp;hxx;hm;inl;inc + + + {be31706d-65c6-4945-b7be-84dcbbcde2e7} + + + {75eb6b5b-331a-4eba-b0b2-687c273e2746} + + + {1efd71b2-ab96-4217-ab65-dbc369ec623f} + + + {d4f35fc6-e668-474b-82af-0771f32cde7f} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files\SourceHook + + + Source Files\SourceHook + + + Source Files\SourceHook + + + Source Files\SourceHook + + + Source Files\SourceHook + + + Source Files\SourceHook + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + Source Files\TestTools + + + + + Header Files\TestTools + + + Header Files\TestTools + + + Header Files\TestTools + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook + + + Header Files\SourceHook\generate + + + Header Files\SourceHook\generate + + + Header Files\SourceHook\generate + + + + + Header Files\SourceHook\generate + + + \ No newline at end of file From 77e74a5eeba43a5b5fa38c842fdeac7ade114740 Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 9 Jul 2015 15:12:16 -0500 Subject: [PATCH 07/44] Partial 64-bit support for SourceHook on Windows --- core/sourcehook/sh_memfuncinfo.h | 9 +- core/sourcehook/test/main.cpp | 2 + core/sourcehook/test/msvc12/test.sln | 12 ++ core/sourcehook/test/msvc12/test.vcxproj | 189 +++++++++++++++++++++++ core/sourcehook/test/testoddthunks.cpp | 27 +++- 5 files changed, 232 insertions(+), 7 deletions(-) diff --git a/core/sourcehook/sh_memfuncinfo.h b/core/sourcehook/sh_memfuncinfo.h index 883e044..ceaa16e 100644 --- a/core/sourcehook/sh_memfuncinfo.h +++ b/core/sourcehook/sh_memfuncinfo.h @@ -125,6 +125,11 @@ namespace SourceHook addr += 2; ok = true; } + else if (addr[0] == 0x48 && addr[1] == 0x8B && addr[2] == 0x01) + { + addr += 3; + ok = true; + } if (!ok) return -1; @@ -132,11 +137,11 @@ namespace SourceHook { if (*addr == 0x60) { - return *++addr / 4; + return *++addr / SH_PTRSIZE; } else if (*addr == 0xA0) { - return *((unsigned int*)++addr) / 4; + return *((unsigned int*)++addr) / SH_PTRSIZE; } else if (*addr == 0x20) return 0; diff --git a/core/sourcehook/test/main.cpp b/core/sourcehook/test/main.cpp index 77a32f2..a4a297a 100644 --- a/core/sourcehook/test/main.cpp +++ b/core/sourcehook/test/main.cpp @@ -78,7 +78,9 @@ int main(int argc, char *argv[]) DO_TEST(RefRet); DO_TEST(VPHooks); DO_TEST(CPageAlloc); +#if !defined( _M_AMD64 ) && !defined( __amd64__ ) // TODO: Fix for 64-bit DO_TEST(HookManGen); +#endif DO_TEST(OddThunks); cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl; diff --git a/core/sourcehook/test/msvc12/test.sln b/core/sourcehook/test/msvc12/test.sln index e69e650..8c9edab 100644 --- a/core/sourcehook/test/msvc12/test.sln +++ b/core/sourcehook/test/msvc12/test.sln @@ -8,19 +8,31 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_NoDebugRuntimeLib|Win32 = Debug_NoDebugRuntimeLib|Win32 + Debug_NoDebugRuntimeLib|x64 = Debug_NoDebugRuntimeLib|x64 Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 DebugOpt|Win32 = DebugOpt|Win32 + DebugOpt|x64 = DebugOpt|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.ActiveCfg = Debug_NoDebugRuntimeLib|Win32 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.Build.0 = Debug_NoDebugRuntimeLib|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|x64.ActiveCfg = Debug_NoDebugRuntimeLib|x64 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|x64.Build.0 = Debug_NoDebugRuntimeLib|x64 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.ActiveCfg = Debug|Win32 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.Build.0 = Debug|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|x64.ActiveCfg = Debug|x64 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|x64.Build.0 = Debug|x64 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.ActiveCfg = DebugOpt|Win32 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.Build.0 = DebugOpt|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|x64.ActiveCfg = DebugOpt|x64 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|x64.Build.0 = DebugOpt|x64 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.ActiveCfg = Release|Win32 {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.Build.0 = Release|Win32 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|x64.ActiveCfg = Release|x64 + {456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/core/sourcehook/test/msvc12/test.vcxproj b/core/sourcehook/test/msvc12/test.vcxproj index cb22fcd..f86fa5c 100644 --- a/core/sourcehook/test/msvc12/test.vcxproj +++ b/core/sourcehook/test/msvc12/test.vcxproj @@ -5,18 +5,34 @@ DebugOpt Win32 + + DebugOpt + x64 + Debug_NoDebugRuntimeLib Win32 + + Debug_NoDebugRuntimeLib + x64 + Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {456BBA64-FF14-4292-8443-3BA79E4D84CC} @@ -29,21 +45,41 @@ v120 MultiByte + + Application + v120 + MultiByte + Application v120 MultiByte + + Application + v120 + MultiByte + Application v120 MultiByte + + Application + v120 + MultiByte + Application v120 MultiByte + + Application + v120 + MultiByte + @@ -51,18 +87,34 @@ + + + + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 @@ -72,21 +124,33 @@ Debug\ true + + true + Release\ Release\ false + + false + DebugOpt\ DebugOpt\ true + + true + Debug_NoDebugRuntimeLib\ Debug_NoDebugRuntimeLib\ true + + true + Disabled @@ -113,6 +177,32 @@ MachineX86 + + + Disabled + Neither + ../..;..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;SH_DEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + true + + + Level3 + ProgramDatabase + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + + + Full @@ -144,6 +234,39 @@ MachineX86 + + + Full + OnlyExplicitInline + Size + true + ../..;..;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + + + + + Level3 + true + ProgramDatabase + + + $(OutDir)test.exe + true + true + true + Console + true + true + false + + + + Full @@ -173,6 +296,36 @@ MachineX86 + + + Full + OnlyExplicitInline + false + Size + true + ..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + Default + MultiThreaded + true + true + + + Level3 + ProgramDatabase + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + + + Disabled @@ -200,6 +353,33 @@ MachineX86 + + + Disabled + Neither + ../..;..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + MultiThreaded + true + true + + + Level3 + ProgramDatabase + + + $(OutDir)test.exe + true + $(OutDir)test.pdb + Console + false + + + + @@ -218,7 +398,9 @@ false + false false + false @@ -237,8 +419,15 @@ pushd ..\..\generate shworker.exe iter sourcehook.hxx sourcehook.h 16 copy sourcehook.h ..\sourcehook.h popd + + echo on +pushd ..\..\generate +shworker.exe iter sourcehook.hxx sourcehook.h 16 +copy sourcehook.h ..\sourcehook.h +popd ..\..\sourcehook.h;%(Outputs) + ..\..\sourcehook.h;%(Outputs) diff --git a/core/sourcehook/test/testoddthunks.cpp b/core/sourcehook/test/testoddthunks.cpp index c0e3917..03980e5 100644 --- a/core/sourcehook/test/testoddthunks.cpp +++ b/core/sourcehook/test/testoddthunks.cpp @@ -96,13 +96,30 @@ namespace // Now generate the jump code g_ThunkAllocator.SetRW(g_OddThunkMemory); - *(base + 0) = 0xE9; // offset jump, immediate operand - ptrdiff_t *offsetAddr = reinterpret_cast(base + 1); - // destination = src + offset + 5 // <=> offset = destination - src - 5 - *offsetAddr = - (reinterpret_cast(origEntry) - base) - 5; + ptrdiff_t offset = reinterpret_cast(origEntry) - base - 5; + + if (offset >= INT_MIN && offset <= INT_MAX) + { + *(base + 0) = 0xE9; // offset jump, immediate operand + ptrdiff_t *offsetAddr = reinterpret_cast(base + 1); + + *offsetAddr = offset; + } + else + { + // mov rax, origEntry + *(base + 0) = 0x48; + *(base + 1) = 0xB8; + void **offsetAddr = reinterpret_cast(reinterpret_cast(base) + 2); + + *offsetAddr = origEntry; + + // jmp rax + *(base + 10) = 0xFF; + *(base + 11) = 0xE0; + } g_ThunkAllocator.SetRE(g_OddThunkMemory); From 95f20333416dfd12eeebe7c779db9b0bae7afb8c Mon Sep 17 00:00:00 2001 From: Scott Ehlert Date: Thu, 9 Jul 2015 16:30:13 -0500 Subject: [PATCH 08/44] Support loading Source 2 game DLL from different paths based on OS and arch. --- loader/gamedll.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index e04a669..1216b68 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -58,10 +58,25 @@ static bool g_is_source2 = false; #if defined _WIN32 #define SERVER_NAME "server.dll" +#if defined _WIN64 +#define PLATFORM_NAME "win64" +#else +#define PLATFORM_NAME "win32" +#endif #elif defined __APPLE__ #define SERVER_NAME "server.dylib" +#if defined __amd64__ +#define PLATFORM_NAME "osx64" +#else +#define PLATFORM_NAME "osx32" +#endif #elif defined __linux__ #define SERVER_NAME "server" LIB_SUFFIX +#if defined __amd64__ +#define PLATFORM_NAME "linuxsteamrt64" +#else +#define PLATFORM_NAME "linuxsteamrt32" +#endif #endif static bool @@ -146,7 +161,7 @@ mm_DetectGameInformation() } char *pRelPath = is_source2 ? "../../" : ""; - char *pOSDir = is_source2 ? "win32/" : ""; + char *pOSDir = is_source2 ? PLATFORM_NAME "/" : ""; if (stricmp(key, "GameBin") == 0) mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s%s/%s" SERVER_NAME, lptr, pRelPath, ptr, pOSDir); else if (!ptr[0]) From 36cb59aada7935596844807aa6040b1ea7fb960a Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 10 Jul 2015 09:30:28 -0400 Subject: [PATCH 09/44] Fix temporary meta_level_init, etc. commands not working. --- core/metamod.cpp | 12 +++++++++++- core/provider/provider_ep2.cpp | 5 +++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 0c501ba..09b7634 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -502,8 +502,11 @@ Handler_GameInit() } is_game_init = true; - +#if SOURCE_ENGINE == SE_SOURCE2 + return true; +#else RETURN_META_VALUE(MRES_IGNORED, true); +#endif } void @@ -551,7 +554,10 @@ Handler_LevelShutdown(void) ITER_EVENT(OnLevelShutdown, ()); +#if SOURCE_ENGINE == SE_SOURCE2 +#else RETURN_META(MRES_IGNORED); +#endif } static bool @@ -564,7 +570,11 @@ Handler_LevelInit(char const *pMapName, { ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); +#if SOURCE_ENGINE == SE_SOURCE2 + return false; +#else RETURN_META_VALUE(MRES_IGNORED, false); +#endif } void MetamodSource::LogMsg(ISmmPlugin *pl, const char *msg, ...) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 41fcfc6..e670d3a 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -168,6 +168,11 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, #endif g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); +#if SOURCE_ENGINE == SE_SOURCE2 + g_SMConVarAccessor.RegisterConCommandBase(&_meta_game_init); + g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_init); + g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_shutdown); +#endif CacheUserMessages(); From ff2e763b992b0611767b19d6d113046ab381be04 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 10 Jul 2015 09:30:51 -0400 Subject: [PATCH 10/44] Fix server exiting on map change. --- core/provider/provider_ep2.cpp | 12 ++++++++++++ core/provider/provider_ep2.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index e670d3a..86026de 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -39,6 +39,14 @@ #include #include "metamod.h" +#if SOURCE_ENGINE == SE_SOURCE2 +SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); +bool BaseProvider::AllowDedicatedServers(EUniverse universe) const +{ + RETURN_META_VALUE(MRES_SUPERCEDE, true); +} +#endif + /* Types */ typedef void (*CONPRINTF_FUNC)(const char *, ...); struct UsrMsgInfo @@ -189,6 +197,10 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, { SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false); } + +#if SOURCE_ENGINE == SE_SOURCE2 + SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &BaseProvider::AllowDedicatedServers), false); +#endif } void BaseProvider::Notify_DLLShutdown_Pre() diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index c83522c..0ac92fd 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -77,6 +77,9 @@ public: virtual const char *GetUserMessage(int index, int *size=NULL); virtual int DetermineSourceEngine(); virtual bool ProcessVDF(const char *file, char path[], size_t path_len, char alias[], size_t alias_len); +#if SOURCE_ENGINE == SE_SOURCE2 + bool AllowDedicatedServers(EUniverse universe) const; +#endif }; extern IVEngineServer *engine; From 1c7fb146ffff0c1090f8d130624574fa397a8726 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 11 Jul 2015 13:58:53 -0400 Subject: [PATCH 11/44] Fix breakage from iserverplugin.h removal. --- core/ISmmAPI.h | 3 ++- core/ISmmPlugin.h | 2 ++ core/provider/provider_ep2.cpp | 1 + core/provider/provider_ep2.h | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/ISmmAPI.h b/core/ISmmAPI.h index 65a01fd..9fc37a3 100644 --- a/core/ISmmAPI.h +++ b/core/ISmmAPI.h @@ -39,7 +39,6 @@ #if defined META_NO_HL2SDK class CGlobalVars; -class IServerPluginCallbacks; struct edict_t; class ConCommandBase; #else @@ -62,6 +61,8 @@ class ConCommandBase; typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); +class IServerPluginCallbacks; + namespace SourceMM { class ISmmPlugin; diff --git a/core/ISmmPlugin.h b/core/ISmmPlugin.h index 12a0665..6b11732 100644 --- a/core/ISmmPlugin.h +++ b/core/ISmmPlugin.h @@ -39,6 +39,8 @@ #include #include +class IServerPluginCallbacks; + // Interface return status, binary-compatible with HL2SDK's IFACE_OK and IFACE_FAILED. enum { diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 86026de..a7904dc 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -38,6 +38,7 @@ #include "metamod_console.h" #include #include "metamod.h" +#include #if SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index 0ac92fd..26dfa89 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -32,7 +32,9 @@ #endif #include #include +#if SOURCE_ENGINE != SE_SOURCE2 #include +#endif #include "ISmmAPI.h" #include "metamod_provider.h" #include "metamod_oslink.h" From a73b63cb5129c80e35d0fafe949d3e31bbeffb40 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 11 Jul 2015 13:59:51 -0400 Subject: [PATCH 12/44] Initial version of GameInit, LevelInit, LevelShutdown hookup; removed cmds to manually trigger them. --- core/metamod.cpp | 238 ++++++++++++++++++++++++++------- core/metamod_provider.h | 8 ++ core/provider/provider_ep2.cpp | 48 +++++-- core/provider/provider_ep2.h | 6 + 4 files changed, 240 insertions(+), 60 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 09b7634..9b23434 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -37,6 +37,9 @@ #if defined __linux__ #include #endif +#if SOURCE_ENGINE == SE_SOURCE2 +#include +#endif using namespace SourceMM; using namespace SourceHook; @@ -47,6 +50,35 @@ using namespace SourceHook::Impl; * @file sourcemm.cpp */ +#if SOURCE_ENGINE == SE_SOURCE2 +// Hack to make hook decl compile when only having forward decl in header. +// (we have class structure but it requires protobuf which we don't want to include here) +class GameSessionConfiguration_t { }; + +SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); +SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); +SH_DECL_MANUALHOOK0(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *); +SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); +SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); + +static INetworkGameServer * +Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *); + +static void +Handler_SwitchToLoop(const char *, KeyValues *, uint32, const char *, bool); + +static void +Handler_StartupServer(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); + +static void +Handler_StartupServer_Post(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); + +static void +Handler_Init(GameSessionConfiguration_t *, const char *); + +static CUtlVector * +Handler_StartChangeLevel(); +#else SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0); @@ -64,6 +96,7 @@ Handler_LevelInit(char const *pMapName, static bool Handler_GameInit(); +#endif static void InitializeVSP(); @@ -142,21 +175,6 @@ SourceMM::ISmmAPI *g_pMetamod = &g_Metamod; } \ } -#if SOURCE_ENGINE == SE_SOURCE2 -void meta_game_init(const CCommand &args) -{ - Handler_GameInit(); -} -void meta_level_init(const CCommand &args) -{ - Handler_LevelInit("dummy_level", "", "", "", false, false); -} -void meta_level_shutdown(const CCommand &args) -{ - Handler_LevelShutdown(); -} -#endif - /* Initialize everything here */ void mm_InitializeForLoad() @@ -171,7 +189,24 @@ mm_InitializeForLoad() */ in_first_level = true; -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE == SE_SOURCE2 + SourceHook::MemFuncInfo info; + + if (!provider->GetHookInfo(ProvidedHook_StartupServer, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkServerService::StartupServer"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_StartupServer, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer), false); + SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer_Post), true); + + if (!provider->GetHookInfo(ProvidedHook_SwitchToLoop, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for IEngineServiceMgr::SwitchToLoop"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_SwitchToLoop, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_SwitchToLoop, enginesvcmgr, SH_STATIC(Handler_SwitchToLoop), false); +#else SourceHook::MemFuncInfo info; if (!provider->GetHookInfo(ProvidedHook_GameInit, &info)) @@ -485,30 +520,6 @@ mm_InitializeGlobals(CreateInterfaceFn engineFactory, provider->Notify_DLLInit_Pre(engineFactory, gamedll_info.factory); } -static bool -Handler_GameInit() -{ - if (is_game_init) - return true; - - if (vsp_load_requested) - InitializeVSP(); - - if (g_bIsVspBridged && !were_plugins_loaded) - { - DoInitialPluginLoads(); - g_PluginMngr.SetAllLoaded(); - were_plugins_loaded = true; - } - - is_game_init = true; -#if SOURCE_ENGINE == SE_SOURCE2 - return true; -#else - RETURN_META_VALUE(MRES_IGNORED, true); -#endif -} - void mm_UnloadMetamod() { @@ -521,8 +532,35 @@ mm_UnloadMetamod() } static void -Handler_LevelShutdown(void) +mm_HandleGameInit() { + if (is_game_init) + return; + +#if SOURCE_ENGINE == SE_SOURCE2 + Msg("MMS: GameInit\n"); +#endif + + if (vsp_load_requested) + InitializeVSP(); + + if (g_bIsVspBridged && !were_plugins_loaded) + { + DoInitialPluginLoads(); + g_PluginMngr.SetAllLoaded(); + were_plugins_loaded = true; + } + + is_game_init = true; +} + +static void +mm_HandleLevelShutdown() +{ +#if SOURCE_ENGINE == SE_SOURCE2 + Msg("MMS: LevelShutdown\n"); +#endif + if (g_bIsVspBridged && !were_plugins_loaded) { DoInitialPluginLoads(); @@ -553,11 +591,120 @@ Handler_LevelShutdown(void) } ITER_EVENT(OnLevelShutdown, ()); +} +static void +mm_HandleLevelInit(char const *pMapName, +char const *pMapEntities, +char const *pOldLevel, +char const *pLandmarkName, +bool loadGame, +bool background) +{ #if SOURCE_ENGINE == SE_SOURCE2 -#else - RETURN_META(MRES_IGNORED); + Msg("MMS: LevelInit\n"); #endif + + ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); +} +#include +#if SOURCE_ENGINE == SE_SOURCE2 +static void +Handler_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk) +{ + if (strcmp(pszLoopName, "levelload") == 0) + { + mm_HandleGameInit(); + } + + RETURN_META(MRES_IGNORED); +} + +static void +Handler_StartupServer(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) +{ + SourceHook::MemFuncInfo info; + if (!provider->GetHookInfo(ProvidedHook_AllocateServer, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServerFactory::Allocate"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_AllocateServer, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); + + RETURN_META(MRES_IGNORED); +} + +static void +Handler_StartupServer_Post(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) +{ + SH_REMOVE_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); + + RETURN_META(MRES_IGNORED); +} + +static INetworkGameServer * +Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *) +{ + static bool bGameServerHooked = false; + if (!bGameServerHooked) + { + INetworkGameServer *netserver = META_RESULT_ORIG_RET(INetworkGameServer *); + + SourceHook::MemFuncInfo info; + if (!provider->GetHookInfo(ProvidedHook_Init, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServer::Init"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_Init, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALVPHOOK(SGD_Init, netserver, SH_STATIC(Handler_Init), false); + + if (!provider->GetHookInfo(ProvidedHook_StartChangeLevel, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServer::StartChangeLevel"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_StartChangeLevel, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALVPHOOK(SGD_StartChangeLevel, netserver, SH_STATIC(Handler_StartChangeLevel), false); + + bGameServerHooked = true; + } + + RETURN_META_VALUE(MRES_IGNORED, nullptr); +} + +static void +Handler_Init(GameSessionConfiguration_t *pConfig, const char *pszMapName) +{ + static char szLastMap[260] = ""; + mm_HandleLevelInit(pszMapName, "", szLastMap, "", false, false); + UTIL_Format(szLastMap, sizeof(szLastMap), "%s", pszMapName); + + RETURN_META(MRES_IGNORED); +} + +static CUtlVector * +Handler_StartChangeLevel() +{ + mm_HandleLevelShutdown(); + + RETURN_META_VALUE(MRES_IGNORED, nullptr); +} + +#else + +static bool +Handler_GameInit() +{ + mm_HandleGameInit(); + + RETURN_META_VALUE(MRES_IGNORED, true); +} + +static void +Handler_LevelShutdown(void) +{ + mm_HandleLevelShutdown(); + + RETURN_META(MRES_IGNORED); } static bool @@ -570,12 +717,9 @@ Handler_LevelInit(char const *pMapName, { ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); -#if SOURCE_ENGINE == SE_SOURCE2 - return false; -#else RETURN_META_VALUE(MRES_IGNORED, false); -#endif } +#endif void MetamodSource::LogMsg(ISmmPlugin *pl, const char *msg, ...) { diff --git a/core/metamod_provider.h b/core/metamod_provider.h index 9cd71be..f16e76a 100644 --- a/core/metamod_provider.h +++ b/core/metamod_provider.h @@ -37,9 +37,17 @@ namespace SourceMM enum ProvidedHooks { +#if SOURCE_ENGINE == SE_SOURCE2 + ProvidedHook_StartChangeLevel = 0, + ProvidedHook_Init = 1, + ProvidedHook_StartupServer = 2, + ProvidedHook_SwitchToLoop = 3, + ProvidedHook_AllocateServer = 4, +#else ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */ ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */ ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */ +#endif }; /** diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index a7904dc..1f6b9c7 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -39,6 +39,9 @@ #include #include "metamod.h" #include +#if SOURCE_ENGINE == SE_SOURCE2 +#include +#endif #if SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); @@ -103,17 +106,14 @@ IFileSystem *baseFs = NULL; IServerGameDLL *server = NULL; #if SOURCE_ENGINE == SE_SOURCE2 static ISource2ServerConfig *serverconfig = NULL; +INetworkServerService *netservice = NULL; +IEngineServiceMgr *enginesvcmgr = NULL; #endif IVEngineServer *engine = NULL; IServerGameClients *gameclients = NULL; CGlobalVars *gpGlobals = NULL; IMetamodSourceProvider *provider = &g_Ep1Provider; ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options"); -#if SOURCE_ENGINE == SE_SOURCE2 -ConCommand _meta_game_init("meta_game_init", meta_game_init); -ConCommand _meta_level_init("meta_level_init", meta_level_init); -ConCommand _meta_level_shutdown("meta_level_shutdown", meta_level_shutdown); -#endif #if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CEntityIndex, const CCommand &); @@ -144,6 +144,8 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, #if SOURCE_ENGINE == SE_SOURCE2 gpGlobals = engine->GetServerGlobals(); serverconfig = (ISource2ServerConfig *) ((serverFactory) (INTERFACEVERSION_SERVERCONFIG, NULL)); + netservice = (INetworkServerService *) ((engineFactory) (NETWORKSERVERSERVICE_INTERFACE_VERSION, NULL)); + enginesvcmgr = (IEngineServiceMgr *) ((engineFactory) (ENGINESERVICEMGR_INTERFACE_VERSION, NULL)); #endif #if SOURCE_ENGINE >= SE_ORANGEBOX icvar = (ICvar *)((engineFactory)(CVAR_INTERFACE_VERSION, NULL)); @@ -177,11 +179,6 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, #endif g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); -#if SOURCE_ENGINE == SE_SOURCE2 - g_SMConVarAccessor.RegisterConCommandBase(&_meta_game_init); - g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_init); - g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_shutdown); -#endif CacheUserMessages(); @@ -308,7 +305,34 @@ bool BaseProvider::LogMessage(const char *buffer) bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) { -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE == SE_SOURCE2 + SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; + + switch (hook) + { + case ProvidedHook_StartupServer: + SourceHook::GetFuncInfo(&INetworkServerService::StartupServer, mfi); + break; + case ProvidedHook_StartChangeLevel: + SourceHook::GetFuncInfo(&INetworkGameServer::StartChangeLevel, mfi); + break; + case ProvidedHook_Init: + SourceHook::GetFuncInfo(&INetworkGameServer::Init, mfi); + break; + case ProvidedHook_SwitchToLoop: + SourceHook::GetFuncInfo(&IEngineServiceMgr::SwitchToLoop, mfi); + break; + case ProvidedHook_AllocateServer: + SourceHook::GetFuncInfo(&INetworkGameServerFactory::Allocate, mfi); + break; + default: + return false; + } + + *pInfo = mfi; + + return (mfi.thisptroffs >= 0); +#else SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; if (hook == ProvidedHook_LevelInit) @@ -327,8 +351,6 @@ bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInf *pInfo = mfi; return (mfi.thisptroffs >= 0); -#else - return false; #endif } diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index 26dfa89..db867dc 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -46,6 +46,8 @@ using namespace SourceMM; using namespace SourceHook; +class INetworkGameServer; + class BaseProvider : public IMetamodSourceProvider { public: @@ -89,6 +91,10 @@ extern IServerGameDLL *server; extern IServerGameClients *gameclients; extern ICvar *icvar; extern CGlobalVars *gpGlobals; +#if SOURCE_ENGINE == SE_SOURCE2 +extern INetworkServerService *netservice; +extern IEngineServiceMgr *enginesvcmgr; +#endif #endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_ From 4461b5e1b896dc3c8007058c8516de3e22af411d Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 31 Aug 2015 14:05:09 -0400 Subject: [PATCH 13/44] Remove hook on AllowDedicatedServer - no longer necessary. --- core/provider/provider_ep2.cpp | 12 --------- loader/gamedll.cpp | 48 +--------------------------------- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 1f6b9c7..80cb575 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -43,14 +43,6 @@ #include #endif -#if SOURCE_ENGINE == SE_SOURCE2 -SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); -bool BaseProvider::AllowDedicatedServers(EUniverse universe) const -{ - RETURN_META_VALUE(MRES_SUPERCEDE, true); -} -#endif - /* Types */ typedef void (*CONPRINTF_FUNC)(const char *, ...); struct UsrMsgInfo @@ -195,10 +187,6 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, { SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false); } - -#if SOURCE_ENGINE == SE_SOURCE2 - SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &BaseProvider::AllowDedicatedServers), false); -#endif } void BaseProvider::Notify_DLLShutdown_Pre() diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 1216b68..1aa5a59 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -52,7 +52,6 @@ static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; -static int is2sc_allowdedi_index = 20; static char mm_path[PLATFORM_MAX_PATH]; static bool g_is_source2 = false; @@ -229,15 +228,11 @@ mm_PatchDllInit(bool patch); static void mm_PatchDllShutdown(); -static void -mm_PatchAllowDedicated(bool patch); - static void mm_PatchConnect(bool patch); static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; -static void *is2sc_orig_allowdedi = NULL; static void *is2sc_orig_connect = NULL; class VEmptyClass @@ -247,9 +242,8 @@ class VEmptyClass gamedll_bridge_info g_bridge_info; // Source2 - Rough start order -// CreateInterfaceFn (IS2SC) - hook Connect and AllowDedicatedServer +// CreateInterfaceFn (IS2SC) - hook Connect // IS2SC::Connect - save factory pointer. return orig. remove hook. -// IS2SC::AllowDedicatedServer - return true. remove hook. // CreateInterfaceFn (IS2S) - hook Init and Shutdown // IS2S::Init - do same as old ISGD::DLLInit, including core load. return orig. remove hook. // IS2S::Shutdown - <-- this @@ -299,11 +293,6 @@ public: return result; } - virtual bool AllowDedicatedServers(int universe) const - { - mm_PatchAllowDedicated(false); - return true; - } }; class ISource2Server @@ -661,40 +650,6 @@ mm_PatchDllShutdown() vtable_dest[isgd_shutdown_index] = vtable_src[mfp.vtblindex]; } -static void -mm_PatchAllowDedicated(bool patch) -{ - void **vtable_src; - void **vtable_dest; - SourceHook::MemFuncInfo mfp; - - SourceHook::GetFuncInfo(&ISource2ServerConfig::AllowDedicatedServers, mfp); - - assert(mfp.isVirtual); - assert(mfp.thisptroffs == 0); - assert(mfp.vtbloffs == 0); - - vtable_src = (void **) *(void **) &is2sc_thunk; - vtable_dest = (void **) *(void **) config_iface; - - SourceHook::SetMemAccess(&vtable_dest[is2sc_allowdedi_index], - sizeof(void*), - SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); - - if (patch) - { - assert(is2sc_orig_allowdedi == NULL); - is2sc_orig_allowdedi = vtable_dest[is2sc_allowdedi_index]; - vtable_dest[is2sc_allowdedi_index] = vtable_src[mfp.vtblindex]; - } - else - { - assert(is2sc_orig_allowdedi != NULL); - vtable_dest[is2sc_allowdedi_index] = is2sc_orig_allowdedi; - is2sc_orig_allowdedi = NULL; - } -} - static void mm_PatchConnect(bool patch) { @@ -776,7 +731,6 @@ mm_GameDllRequest(const char *name, int *ret) gamedll_qvi = qvi; mm_PatchConnect(true); - mm_PatchAllowDedicated(true); if (ret != NULL) *ret = 0; From c07bab9763ea57b0c02d4f20f6041842a4047e65 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 31 Aug 2015 14:59:29 -0400 Subject: [PATCH 14/44] Hook Connect on ISource2Server instead of ISource2ServerConfig. --- loader/gamedll.cpp | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 1aa5a59..cd4fc52 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -36,7 +36,6 @@ #include "gamedll.h" class IServerGameDLL; -class ISource2ServerConfig; #define MAX_GAMEDLL_PATHS 10 @@ -48,7 +47,6 @@ static void *gamedll_libs[MAX_GAMEDLL_PATHS]; static unsigned int gamedll_path_count = 0; static void *gamedll_lib = NULL; static IServerGameDLL *gamedll_iface = NULL; -static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; @@ -233,7 +231,7 @@ mm_PatchConnect(bool patch); static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; -static void *is2sc_orig_connect = NULL; +static void *is2s_orig_connect = NULL; class VEmptyClass { @@ -256,10 +254,10 @@ enum InitReturnVal_t INIT_LAST_VAL, }; -class ISource2ServerConfig +class ISource2Server { public: - virtual bool Connect(QueryValveInterface factory) + virtual bool Connect(QueryValveInterface factory) { g_bridge_info.engineFactory = factory; g_bridge_info.fsFactory = factory; @@ -275,7 +273,7 @@ public: #if defined _WIN32 void *addr; } u; - u.addr = is2sc_orig_connect; + u.addr = is2s_orig_connect; #else struct { @@ -283,22 +281,16 @@ public: intptr_t adjustor; } s; } u; - u.s.addr = is2sc_orig_connect; + u.s.addr = is2s_orig_connect; u.s.adjustor = 0; #endif - result = (((VEmptyClass *) config_iface)->*u.mfpnew)(factory); - } + result = (((VEmptyClass *) gamedll_iface)->*u.mfpnew)(factory); + } mm_PatchConnect(false); return result; } -}; - -class ISource2Server -{ -public: - virtual bool Connect(QueryValveInterface factory) { return true; } virtual void Disconnect() {} virtual void *QueryInterface(const char *pInterfaceName) { return nullptr; } @@ -566,7 +558,6 @@ public: static IServerGameDLL isgd_thunk; static ISource2Server is2s_thunk; -static ISource2ServerConfig is2sc_thunk; static void mm_PatchDllInit(bool patch) @@ -657,14 +648,14 @@ mm_PatchConnect(bool patch) void **vtable_dest; SourceHook::MemFuncInfo mfp; - SourceHook::GetFuncInfo(&ISource2ServerConfig::Connect, mfp); + SourceHook::GetFuncInfo(&ISource2Server::Connect, mfp); assert(mfp.isVirtual); assert(mfp.thisptroffs == 0); assert(mfp.vtbloffs == 0); - vtable_src = (void **) *(void **) &is2sc_thunk; - vtable_dest = (void **) *(void **) config_iface; + vtable_src = (void **) *(void **) &is2s_thunk; + vtable_dest = (void **) *(void **) gamedll_iface; SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], sizeof(void*), @@ -672,15 +663,15 @@ mm_PatchConnect(bool patch) if (patch) { - assert(is2sc_orig_connect == NULL); - is2sc_orig_connect = vtable_dest[mfp.vtblindex]; + assert(is2s_orig_connect == NULL); + is2s_orig_connect = vtable_dest[mfp.vtblindex]; vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; } else { - assert(is2sc_orig_connect != NULL); - vtable_dest[mfp.vtblindex] = is2sc_orig_connect; - is2sc_orig_connect = NULL; + assert(is2s_orig_connect != NULL); + vtable_dest[mfp.vtblindex] = is2s_orig_connect; + is2s_orig_connect = NULL; } } @@ -727,11 +718,8 @@ mm_GameDllRequest(const char *name, int *ret) { mm_FreeCachedLibraries(); gamedll_lib = lib; - config_iface = (ISource2ServerConfig *) ptr; gamedll_qvi = qvi; - mm_PatchConnect(true); - if (ret != NULL) *ret = 0; return ptr; @@ -741,6 +729,7 @@ mm_GameDllRequest(const char *name, int *ret) { gamedll_iface = (IServerGameDLL *)gamedll_qvi(name, ret); gamedll_version = atoi(&name[13]); + mm_PatchConnect(true); mm_PatchDllInit(true); if (ret != NULL) From 5ecfdcaa2b4c742bc396d1c71d022662205a2918 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 21 Sep 2015 13:28:52 -0400 Subject: [PATCH 15/44] Revert "Hook Connect on ISource2Server instead of ISource2ServerConfig." This reverts commit c07bab9763ea57b0c02d4f20f6041842a4047e65. --- loader/gamedll.cpp | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index cd4fc52..1aa5a59 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -36,6 +36,7 @@ #include "gamedll.h" class IServerGameDLL; +class ISource2ServerConfig; #define MAX_GAMEDLL_PATHS 10 @@ -47,6 +48,7 @@ static void *gamedll_libs[MAX_GAMEDLL_PATHS]; static unsigned int gamedll_path_count = 0; static void *gamedll_lib = NULL; static IServerGameDLL *gamedll_iface = NULL; +static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; @@ -231,7 +233,7 @@ mm_PatchConnect(bool patch); static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; -static void *is2s_orig_connect = NULL; +static void *is2sc_orig_connect = NULL; class VEmptyClass { @@ -254,10 +256,10 @@ enum InitReturnVal_t INIT_LAST_VAL, }; -class ISource2Server +class ISource2ServerConfig { public: - virtual bool Connect(QueryValveInterface factory) + virtual bool Connect(QueryValveInterface factory) { g_bridge_info.engineFactory = factory; g_bridge_info.fsFactory = factory; @@ -273,7 +275,7 @@ public: #if defined _WIN32 void *addr; } u; - u.addr = is2s_orig_connect; + u.addr = is2sc_orig_connect; #else struct { @@ -281,16 +283,22 @@ public: intptr_t adjustor; } s; } u; - u.s.addr = is2s_orig_connect; + u.s.addr = is2sc_orig_connect; u.s.adjustor = 0; #endif - result = (((VEmptyClass *) gamedll_iface)->*u.mfpnew)(factory); - } + result = (((VEmptyClass *) config_iface)->*u.mfpnew)(factory); + } mm_PatchConnect(false); return result; } +}; + +class ISource2Server +{ +public: + virtual bool Connect(QueryValveInterface factory) { return true; } virtual void Disconnect() {} virtual void *QueryInterface(const char *pInterfaceName) { return nullptr; } @@ -558,6 +566,7 @@ public: static IServerGameDLL isgd_thunk; static ISource2Server is2s_thunk; +static ISource2ServerConfig is2sc_thunk; static void mm_PatchDllInit(bool patch) @@ -648,14 +657,14 @@ mm_PatchConnect(bool patch) void **vtable_dest; SourceHook::MemFuncInfo mfp; - SourceHook::GetFuncInfo(&ISource2Server::Connect, mfp); + SourceHook::GetFuncInfo(&ISource2ServerConfig::Connect, mfp); assert(mfp.isVirtual); assert(mfp.thisptroffs == 0); assert(mfp.vtbloffs == 0); - vtable_src = (void **) *(void **) &is2s_thunk; - vtable_dest = (void **) *(void **) gamedll_iface; + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex], sizeof(void*), @@ -663,15 +672,15 @@ mm_PatchConnect(bool patch) if (patch) { - assert(is2s_orig_connect == NULL); - is2s_orig_connect = vtable_dest[mfp.vtblindex]; + assert(is2sc_orig_connect == NULL); + is2sc_orig_connect = vtable_dest[mfp.vtblindex]; vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex]; } else { - assert(is2s_orig_connect != NULL); - vtable_dest[mfp.vtblindex] = is2s_orig_connect; - is2s_orig_connect = NULL; + assert(is2sc_orig_connect != NULL); + vtable_dest[mfp.vtblindex] = is2sc_orig_connect; + is2sc_orig_connect = NULL; } } @@ -718,8 +727,11 @@ mm_GameDllRequest(const char *name, int *ret) { mm_FreeCachedLibraries(); gamedll_lib = lib; + config_iface = (ISource2ServerConfig *) ptr; gamedll_qvi = qvi; + mm_PatchConnect(true); + if (ret != NULL) *ret = 0; return ptr; @@ -729,7 +741,6 @@ mm_GameDllRequest(const char *name, int *ret) { gamedll_iface = (IServerGameDLL *)gamedll_qvi(name, ret); gamedll_version = atoi(&name[13]); - mm_PatchConnect(true); mm_PatchDllInit(true); if (ret != NULL) From 112cbcaa3a23c99ca72f2037d931574ddeb9f539 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 21 Sep 2015 13:29:01 -0400 Subject: [PATCH 16/44] Revert "Remove hook on AllowDedicatedServer - no longer necessary." This reverts commit 4461b5e1b896dc3c8007058c8516de3e22af411d. --- core/provider/provider_ep2.cpp | 12 +++++++++ loader/gamedll.cpp | 48 +++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 80cb575..1f6b9c7 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -43,6 +43,14 @@ #include #endif +#if SOURCE_ENGINE == SE_SOURCE2 +SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); +bool BaseProvider::AllowDedicatedServers(EUniverse universe) const +{ + RETURN_META_VALUE(MRES_SUPERCEDE, true); +} +#endif + /* Types */ typedef void (*CONPRINTF_FUNC)(const char *, ...); struct UsrMsgInfo @@ -187,6 +195,10 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, { SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false); } + +#if SOURCE_ENGINE == SE_SOURCE2 + SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &BaseProvider::AllowDedicatedServers), false); +#endif } void BaseProvider::Notify_DLLShutdown_Pre() diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 1aa5a59..1216b68 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -52,6 +52,7 @@ static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; +static int is2sc_allowdedi_index = 20; static char mm_path[PLATFORM_MAX_PATH]; static bool g_is_source2 = false; @@ -228,11 +229,15 @@ mm_PatchDllInit(bool patch); static void mm_PatchDllShutdown(); +static void +mm_PatchAllowDedicated(bool patch); + static void mm_PatchConnect(bool patch); static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; +static void *is2sc_orig_allowdedi = NULL; static void *is2sc_orig_connect = NULL; class VEmptyClass @@ -242,8 +247,9 @@ class VEmptyClass gamedll_bridge_info g_bridge_info; // Source2 - Rough start order -// CreateInterfaceFn (IS2SC) - hook Connect +// CreateInterfaceFn (IS2SC) - hook Connect and AllowDedicatedServer // IS2SC::Connect - save factory pointer. return orig. remove hook. +// IS2SC::AllowDedicatedServer - return true. remove hook. // CreateInterfaceFn (IS2S) - hook Init and Shutdown // IS2S::Init - do same as old ISGD::DLLInit, including core load. return orig. remove hook. // IS2S::Shutdown - <-- this @@ -293,6 +299,11 @@ public: return result; } + virtual bool AllowDedicatedServers(int universe) const + { + mm_PatchAllowDedicated(false); + return true; + } }; class ISource2Server @@ -650,6 +661,40 @@ mm_PatchDllShutdown() vtable_dest[isgd_shutdown_index] = vtable_src[mfp.vtblindex]; } +static void +mm_PatchAllowDedicated(bool patch) +{ + void **vtable_src; + void **vtable_dest; + SourceHook::MemFuncInfo mfp; + + SourceHook::GetFuncInfo(&ISource2ServerConfig::AllowDedicatedServers, mfp); + + assert(mfp.isVirtual); + assert(mfp.thisptroffs == 0); + assert(mfp.vtbloffs == 0); + + vtable_src = (void **) *(void **) &is2sc_thunk; + vtable_dest = (void **) *(void **) config_iface; + + SourceHook::SetMemAccess(&vtable_dest[is2sc_allowdedi_index], + sizeof(void*), + SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + if (patch) + { + assert(is2sc_orig_allowdedi == NULL); + is2sc_orig_allowdedi = vtable_dest[is2sc_allowdedi_index]; + vtable_dest[is2sc_allowdedi_index] = vtable_src[mfp.vtblindex]; + } + else + { + assert(is2sc_orig_allowdedi != NULL); + vtable_dest[is2sc_allowdedi_index] = is2sc_orig_allowdedi; + is2sc_orig_allowdedi = NULL; + } +} + static void mm_PatchConnect(bool patch) { @@ -731,6 +776,7 @@ mm_GameDllRequest(const char *name, int *ret) gamedll_qvi = qvi; mm_PatchConnect(true); + mm_PatchAllowDedicated(true); if (ret != NULL) *ret = 0; From c9dae39e6b969ae5324a9fd371c90efcef18aabb Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Tue, 22 Sep 2015 07:33:27 -0400 Subject: [PATCH 17/44] Update offset for AllowDedicatedServer in loader. --- loader/gamedll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 1216b68..5ee2779 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -52,7 +52,7 @@ static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; -static int is2sc_allowdedi_index = 20; +static int is2sc_allowdedi_index = 22; static char mm_path[PLATFORM_MAX_PATH]; static bool g_is_source2 = false; From 81d297312962730bd6529543c8aa273ec2b1a677 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Tue, 22 Sep 2015 07:33:50 -0400 Subject: [PATCH 18/44] Disable VDF plugin loading on Source2 until KV issues are worked out. --- core/provider/provider_ep2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 1f6b9c7..19f7350 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -525,7 +525,9 @@ ConVar *BaseProvider::CreateConVar(const char *name, bool BaseProvider::ProcessVDF(const char *file, char path[], size_t path_len, char alias[], size_t alias_len) { +#if SOURCE_ENGINE != SE_SOURCE2 if (baseFs == NULL) +#endif { return false; } From 508f39ae1bfb4ae400566932ff0b955dbfd4fcc8 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 8 Oct 2015 12:55:34 -0400 Subject: [PATCH 19/44] Re-enable plugin loading from VDF. --- core/provider/provider_ep2.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 19f7350..1f6b9c7 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -525,9 +525,7 @@ ConVar *BaseProvider::CreateConVar(const char *name, bool BaseProvider::ProcessVDF(const char *file, char path[], size_t path_len, char alias[], size_t alias_len) { -#if SOURCE_ENGINE != SE_SOURCE2 if (baseFs == NULL) -#endif { return false; } From 1045cdb98e878e6ca0643c2a91ddaa11af4b00e3 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Thu, 8 Oct 2015 12:57:56 -0400 Subject: [PATCH 20/44] Remove MM:S dir from search paths. --- core/provider/provider_ep2.cpp | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 1f6b9c7..2b51b60 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -174,6 +174,41 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, mm_LogMessage("Unable to find \"%s\": .vdf files will not be parsed", FILESYSTEM_INTERFACE_VERSION); } +#if SOURCE_ENGINE == SE_SOURCE2 + // Since we have to be added as a Game path (cannot add GameBin directly), we + // automatically get added to other paths as well, including having the MM:S + // dir become the default write path for logs and more. We can fix some of these. + + char searchPath[260]; + baseFs->GetSearchPath("GAME", (GetSearchPathTypes_t)0, searchPath, sizeof(searchPath)); + for (int i = 0; i < sizeof(searchPath); ++i) + { + if (searchPath[i] == ';') + { + searchPath[i] = '\0'; + break; + } + } + baseFs->RemoveSearchPath(searchPath, "GAME"); + + // TODO: figure out why these calls get ignored and path remains + //baseFs->RemoveSearchPath(searchPath, "CONTENT"); + //baseFs->RemoveSearchPath(searchPath, "SHADER_SOURCE"); + //baseFs->RemoveSearchPath(searchPath, "SHADER_SOURCE_MOD"); + + baseFs->RemoveSearchPaths("DEFAULT_WRITE_PATH"); + baseFs->GetSearchPath("GAME", (GetSearchPathTypes_t)0, searchPath, sizeof(searchPath)); + for (int i = 0; i < sizeof(searchPath); ++i) + { + if (searchPath[i] == ';') + { + searchPath[i] = '\0'; + break; + } + } + baseFs->AddSearchPath(searchPath, "DEFAULT_WRITE_PATH"); +#endif + #if SOURCE_ENGINE >= SE_ORANGEBOX g_pCVar = icvar; #endif From 68dcd2e40e62381102e2a7bd3ae5ccbd6cce0ad0 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 18 Dec 2015 08:42:19 -0500 Subject: [PATCH 21/44] Fix AMbuild script. --- AMBuildScript | 3 --- 1 file changed, 3 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index c147c09..6b07f2a 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -115,9 +115,6 @@ class MMSConfig(object): cfg = builder.DetectCompilers() cxx = cfg.cxx - if builder.options.source2 == '1': - cfg.defines += ['SOURCE2_BUILD=1'] - if cxx.behavior == 'gcc': cfg.defines += [ 'stricmp=strcasecmp', From 4472cc4cc7fad46834e00ecd865958b44d086fe0 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 18 Dec 2015 08:42:41 -0500 Subject: [PATCH 22/44] Update AllowDedicatedServers offset in loader. --- loader/gamedll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 5ee2779..12fb6c1 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -52,7 +52,7 @@ static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; -static int is2sc_allowdedi_index = 22; +static int is2sc_allowdedi_index = 21; static char mm_path[PLATFORM_MAX_PATH]; static bool g_is_source2 = false; From 366a27e10ce4705bb5527627ffbef72c57565085 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 13:57:54 -0400 Subject: [PATCH 23/44] Ditch "source2" naming, restoring "dota". --- AMBuildScript | 11 +++---- core/ISmmPluginExt.h | 1 - core/gamedll_bridge.cpp | 2 +- core/metamod.cpp | 16 +++++----- core/metamod.h | 2 +- core/metamod_console.cpp | 10 +++--- core/metamod_console.h | 2 +- core/metamod_provider.h | 2 +- core/provider/provider_ep2.cpp | 57 ++++++++++++++-------------------- core/provider/provider_ep2.h | 6 ++-- core/vsp_bridge.cpp | 8 ++--- loader/gamedll.cpp | 2 +- loader/loader.cpp | 3 +- loader/loader.h | 1 - 14 files changed, 53 insertions(+), 70 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 6b07f2a..57486ed 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -32,13 +32,12 @@ PossibleSDKs = { 'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'), 'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'), 'csgo': SDK('HL2SDKCSGO', '2.csgo', '20', 'CSGO', WinLinuxMac, 'csgo'), - 'dota': SDK('HL2SDKDOTA', '2.dota', '21', 'DOTA', [], 'dota'), + 'dota': SDK('HL2SDKDOTA', '2.dota', '21', 'DOTA', WinLinux, 'dota'), 'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'), 'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'), 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), - 'source2': SDK('HL2SDKSOURCE2', '2.source2', '22', 'SOURCE2', WinOnly, 'source2'), } def ResolveEnvPath(env, folder): @@ -281,7 +280,7 @@ class MMSConfig(object): else: compiler.defines += ['COMPILER_GCC'] - if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota', 'source2']: + if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: if builder.target_platform in ['linux', 'mac']: compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] @@ -357,7 +356,7 @@ class MMSConfig(object): else: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a'))] - if sdk.name in ['blade', 'insurgency', 'csgo', 'dota', 'source2']: + if sdk.name in ['blade', 'insurgency', 'csgo', 'dota']: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))] binary = self.LibraryBuilder(compiler, name) @@ -367,7 +366,7 @@ class MMSConfig(object): compiler.linkflags[0:0] = ['-lm'] if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency']: dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] - elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota', 'source2']: + elif sdk.name in ['l4d', 'blade', 'insurgency', 'csgo', 'dota']: dynamic_libs = ['libtier0.so', 'libvstdlib.so'] else: dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] @@ -376,7 +375,7 @@ class MMSConfig(object): dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] elif builder.target_platform == 'windows': libs = ['tier0', 'tier1', 'vstdlib'] - if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota', 'source2']: + if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']: libs.append('interfaces') for lib in libs: lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' diff --git a/core/ISmmPluginExt.h b/core/ISmmPluginExt.h index 31b6cb2..4f245a5 100644 --- a/core/ISmmPluginExt.h +++ b/core/ISmmPluginExt.h @@ -59,7 +59,6 @@ #define SOURCE_ENGINE_INSURGENCY 21 /**< Insurgency */ #define SOURCE_ENGINE_CONTAGION 22 /**< Contagion */ #define SOURCE_ENGINE_BMS 23 /**< Black Mesa Multiplayer */ -#define SOURCE_ENGINE_SOURCE2 24 #define METAMOD_PLAPI_VERSION 15 /**< Version of this header file */ #define METAMOD_PLAPI_NAME "ISmmPlugin" /**< Name of the plugin interface */ diff --git a/core/gamedll_bridge.cpp b/core/gamedll_bridge.cpp index 8efe541..9c8c34b 100644 --- a/core/gamedll_bridge.cpp +++ b/core/gamedll_bridge.cpp @@ -63,7 +63,7 @@ public: SourceHook::MemFuncInfo mfi; mfi.isVirtual = false; -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SourceHook::GetFuncInfo(&IServerGameDLL::Shutdown, mfi); #else SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi); diff --git a/core/metamod.cpp b/core/metamod.cpp index 9b23434..d283c4b 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -37,7 +37,7 @@ #if defined __linux__ #include #endif -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA #include #endif @@ -50,7 +50,7 @@ using namespace SourceHook::Impl; * @file sourcemm.cpp */ -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA // Hack to make hook decl compile when only having forward decl in header. // (we have class structure but it requires protobuf which we don't want to include here) class GameSessionConfiguration_t { }; @@ -189,7 +189,7 @@ mm_InitializeForLoad() */ in_first_level = true; -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SourceHook::MemFuncInfo info; if (!provider->GetHookInfo(ProvidedHook_StartupServer, &info)) @@ -537,7 +537,7 @@ mm_HandleGameInit() if (is_game_init) return; -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA Msg("MMS: GameInit\n"); #endif @@ -557,7 +557,7 @@ mm_HandleGameInit() static void mm_HandleLevelShutdown() { -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA Msg("MMS: LevelShutdown\n"); #endif @@ -601,14 +601,14 @@ char const *pLandmarkName, bool loadGame, bool background) { -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA Msg("MMS: LevelInit\n"); #endif ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); } #include -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA static void Handler_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk) { @@ -943,7 +943,7 @@ size_t MetamodSource::PathFormat(char *buffer, size_t len, const char *fmt, ...) return mylen; } -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA void MetamodSource::ClientConPrintf(int clientIndex, const char *fmt, ...) { va_list ap; diff --git a/core/metamod.h b/core/metamod.h index c7e1057..07a2b38 100644 --- a/core/metamod.h +++ b/core/metamod.h @@ -76,7 +76,7 @@ public: void *InterfaceSearch(CreateInterfaceFn fn, const char *iface, int max, int *ret); const char *GetBaseDir(); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA // Shim void ClientConPrintf(int clientIndex, const char *fmt, ...); #endif diff --git a/core/metamod_console.cpp b/core/metamod_console.cpp index 392422c..2bd9c86 100644 --- a/core/metamod_console.cpp +++ b/core/metamod_console.cpp @@ -44,7 +44,7 @@ using namespace SourceHook; #define CLIENT_CONMSG g_Metamod.ClientConPrintf template -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA void CMDMSG(int client, const char *pMsg, Ts ... ts) #else void CMDMSG(edict_t *client, const char *pMsg, Ts ... ts) @@ -100,13 +100,11 @@ void CMDMSG(edict_t *client, const char *pMsg, Ts ... ts) #define MMS_ENGINE_NAME "Counter-Strike: Global Offensive (2012)" #elif SOURCE_ENGINE == SE_DOTA #define MMS_ENGINE_NAME "Dota 2 (2013)" -#elif SOURCE_ENGINE == SE_SOURCE2 -#define MMS_ENGINE_NAME "Source 2" #else #error "SOURCE_ENGINE not defined to a known value" #endif -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA static void ReplyCredits(int client = 0) #else static void ReplyCredits(edict_t *client = nullptr) @@ -120,7 +118,7 @@ static void ReplyCredits(edict_t *client = nullptr) CMDMSG(client, "http://www.metamodsource.net/\n"); } -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA static void ReplyVersion(int client = 0) #else static void ReplyVersion(edict_t *client = nullptr) @@ -700,7 +698,7 @@ bool Command_Meta(IMetamodSourceCommandInfo *info) return true; } -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA bool Command_ClientMeta(int client, IMetamodSourceCommandInfo *info) #else bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info) diff --git a/core/metamod_console.h b/core/metamod_console.h index 20e5bd7..ef3d529 100644 --- a/core/metamod_console.h +++ b/core/metamod_console.h @@ -31,7 +31,7 @@ #include "metamod_provider.h" bool Command_Meta(IMetamodSourceCommandInfo *info); -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA bool Command_ClientMeta(int client, IMetamodSourceCommandInfo *info); #else bool Command_ClientMeta(edict_t *client, IMetamodSourceCommandInfo *info); diff --git a/core/metamod_provider.h b/core/metamod_provider.h index f16e76a..408fd48 100644 --- a/core/metamod_provider.h +++ b/core/metamod_provider.h @@ -37,7 +37,7 @@ namespace SourceMM enum ProvidedHooks { -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA ProvidedHook_StartChangeLevel = 0, ProvidedHook_Init = 1, ProvidedHook_StartupServer = 2, diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index a864e7a..3a0337f 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -39,11 +39,11 @@ #include #include "metamod.h" #include -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA #include #endif -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); bool BaseProvider::AllowDedicatedServers(EUniverse universe) const { @@ -74,23 +74,18 @@ DLL_IMPORT ICommandLine *CommandLine(); /* Functions */ void CacheUserMessages(); void Detour_Error(const tchar *pMsg, ...); -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 -void ClientCommand(CEntityIndex index, const CCommand &args); + #if SOURCE_ENGINE == SE_DOTA -void LocalCommand_Meta(const CCommandContext &context, const CCommand &args); -#else -void LocalCommand_Meta(const CCommand &args); -#endif -#if SOURCE_ENGINE == SE_SOURCE2 -void meta_game_init(const CCommand &args); -void meta_level_init(const CCommand &args); -void meta_level_shutdown(const CCommand &args); -#endif +void ClientCommand(CEntityIndex index, const CCommand &args); #elif SOURCE_ENGINE >= SE_ORANGEBOX void ClientCommand(edict_t *pEdict, const CCommand &args); -void LocalCommand_Meta(const CCommand &args); #else void ClientCommand(edict_t *pEdict); +#endif + +#if SOURCE_ENGINE >= SE_ORANGEBOX +void LocalCommand_Meta(const CCommand &args); +#else void LocalCommand_Meta(); #endif @@ -104,7 +99,7 @@ static jmp_buf usermsg_end; ICvar *icvar = NULL; IFileSystem *baseFs = NULL; IServerGameDLL *server = NULL; -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA static ISource2ServerConfig *serverconfig = NULL; INetworkServerService *netservice = NULL; IEngineServiceMgr *enginesvcmgr = NULL; @@ -115,7 +110,7 @@ CGlobalVars *gpGlobals = NULL; IMetamodSourceProvider *provider = &g_Ep1Provider; ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options"); -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CEntityIndex, const CCommand &); #elif SOURCE_ENGINE >= SE_ORANGEBOX SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &); @@ -154,7 +149,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, DisplayError("Could not find IVEngineServer! Metamod cannot load."); return; } -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA gpGlobals = engine->GetServerGlobals(); serverconfig = (ISource2ServerConfig *) ((serverFactory) (INTERFACEVERSION_SERVERCONFIG, NULL)); netservice = (INetworkServerService *) ((engineFactory) (NETWORKSERVERSERVICE_INTERFACE_VERSION, NULL)); @@ -171,7 +166,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, return; } -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA gameclients = (IServerGameClients *)(serverFactory(INTERFACEVERSION_SERVERGAMECLIENTS, NULL)); #else if ((gameclients = (IServerGameClients *)(serverFactory("ServerGameClients003", NULL))) @@ -187,7 +182,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, mm_LogMessage("Unable to find \"%s\": .vdf files will not be parsed", FILESYSTEM_INTERFACE_VERSION); } -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA // Since we have to be added as a Game path (cannot add GameBin directly), we // automatically get added to other paths as well, including having the MM:S // dir become the default write path for logs and more. We can fix some of these. @@ -244,7 +239,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false); } -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &BaseProvider::AllowDedicatedServers), false); #endif } @@ -269,7 +264,7 @@ bool BaseProvider::IsRemotePrintingAvailable() void BaseProvider::ClientConsolePrint(edict_t *pEdict, const char *message) { -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA int client = (int)(pEdict - gpGlobals->pEdicts); engine->ClientPrintf(client, message); #else @@ -353,7 +348,7 @@ bool BaseProvider::LogMessage(const char *buffer) bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) { -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; switch (hook) @@ -411,7 +406,7 @@ void BaseProvider::DisplayError(const char *fmt, ...) UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA Msg("ERROR: %s", buffer); #else Error("%s", buffer); @@ -447,7 +442,7 @@ void BaseProvider::UnregisterConCommandBase(ConCommandBase *pCommand) int BaseProvider::GetUserMessageCount() { -#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA return -1; #else return (int)usermsgs_list.size(); @@ -493,7 +488,7 @@ void BaseProvider::GetGamePath(char *pszBuffer, int len) const char *BaseProvider::GetGameDescription() { -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA return serverconfig->GetGameDescription(); #else return server->GetGameDescription(); @@ -542,8 +537,6 @@ int BaseProvider::DetermineSourceEngine() return SOURCE_ENGINE_DOTA; #elif SOURCE_ENGINE == SE_BMS return SOURCE_ENGINE_BMS; -#elif SOURCE_ENGINE == SE_SOURCE2 - return SOURCE_ENGINE_SOURCE2; #else #error "SOURCE_ENGINE not defined to a known value" #endif @@ -657,11 +650,7 @@ public: }; #endif -#if SOURCE_ENGINE == SE_DOTA// || SOURCE_ENGINE == SE_SOURCE2 -void LocalCommand_Meta(const CCommandContext &context, const CCommand &args) -{ - GlobCommand cmd(&args); -#elif SOURCE_ENGINE >= SE_ORANGEBOX +#if SOURCE_ENGINE >= SE_ORANGEBOX void LocalCommand_Meta(const CCommand &args) { GlobCommand cmd(&args); @@ -673,7 +662,7 @@ void LocalCommand_Meta() Command_Meta(&cmd); } -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA void ClientCommand(CEntityIndex index, const CCommand &_cmd) { int client = index.Get(); @@ -696,7 +685,7 @@ void ClientCommand(edict_t *client) RETURN_META(MRES_IGNORED); } -#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA void CacheUserMessages() { diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index db867dc..fe46da6 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -32,7 +32,7 @@ #endif #include #include -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE != SE_DOTA #include #endif #include "ISmmAPI.h" @@ -81,7 +81,7 @@ public: virtual const char *GetUserMessage(int index, int *size=NULL); virtual int DetermineSourceEngine(); virtual bool ProcessVDF(const char *file, char path[], size_t path_len, char alias[], size_t alias_len); -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA bool AllowDedicatedServers(EUniverse universe) const; #endif }; @@ -91,7 +91,7 @@ extern IServerGameDLL *server; extern IServerGameClients *gameclients; extern ICvar *icvar; extern CGlobalVars *gpGlobals; -#if SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA extern INetworkServerService *netservice; extern IEngineServiceMgr *enginesvcmgr; #endif diff --git a/core/vsp_bridge.cpp b/core/vsp_bridge.cpp index c6d0681..ab24824 100644 --- a/core/vsp_bridge.cpp +++ b/core/vsp_bridge.cpp @@ -34,7 +34,7 @@ #include #include "provider/provider_ep2.h" -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA SH_DECL_HOOK2_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommandContext &, const CCommand &); #elif SOURCE_ENGINE >= SE_ORANGEBOX SH_DECL_HOOK1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &); @@ -46,7 +46,7 @@ ConCommand *g_plugin_unload = NULL; bool g_bIsTryingToUnload; SourceHook::String vsp_desc("Metamod:Source"); -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA void InterceptPluginUnloads(const CCommandContext &context, const CCommand &args) #elif SOURCE_ENGINE >= SE_ORANGEBOX void InterceptPluginUnloads(const CCommand &args) @@ -57,7 +57,7 @@ void InterceptPluginUnloads() g_bIsTryingToUnload = true; } -#if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 +#if SOURCE_ENGINE == SE_DOTA void InterceptPluginUnloads_Post(const CCommandContext &context, const CCommand &args) #elif SOURCE_ENGINE >= SE_ORANGEBOX void InterceptPluginUnloads_Post(const CCommand &args) @@ -165,7 +165,7 @@ public: virtual void Unload() { // Source2 doesn't have the Error function (nor VSP support). -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE != SE_DOTA if (g_bIsTryingToUnload) { Error("Metamod:Source cannot be unloaded from VSP mode. Use \"meta unload\" to unload specific plugins.\n"); diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 12fb6c1..2726e1a 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -315,7 +315,7 @@ public: virtual InitReturnVal_t Init() { - mm_backend = MMBackend_Source2; + mm_backend = MMBackend_DOTA; char error[255]; if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) diff --git a/loader/loader.cpp b/loader/loader.cpp index 834dbaf..e768e01 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -89,8 +89,7 @@ static const char *backend_names[] = "2.blade", "2.insurgency", "2.contagion", - "2.bms", - "2.source2" + "2.bms" }; #if defined _WIN32 diff --git a/loader/loader.h b/loader/loader.h index ef22666..9134217 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -102,7 +102,6 @@ enum MetamodBackend MMBackend_Insurgency, MMBackend_Contagion, MMBackend_BMS, - MMBackend_Source2, MMBackend_UNKNOWN }; From 4007ae8310c8c0dd07a6af59dab057ecf9b3a3cb Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 13:59:58 -0400 Subject: [PATCH 24/44] Disable dynamic hooking iface on non-Windows Dota. This should really be disabled on x64 (or ported to work on it), but not sure how to best check that in the AMBuilder file. --- core/AMBuilder | 5 ++++- core/metamod.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/AMBuilder b/core/AMBuilder index 5b15887..00d8f54 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -18,7 +18,6 @@ for sdk_name in MMS.sdks: 'provider/console.cpp', 'provider/provider_ep2.cpp', 'sourcehook/sourcehook.cpp', - 'sourcehook/sourcehook_hookmangen.cpp', 'sourcehook/sourcehook_impl_chookidman.cpp', 'sourcehook/sourcehook_impl_chookmaninfo.cpp', 'sourcehook/sourcehook_impl_cproto.cpp', @@ -26,5 +25,9 @@ for sdk_name in MMS.sdks: 'gamedll_bridge.cpp', 'vsp_bridge.cpp' ] + + # Source2 hack. TODO: check this more deterministically, "are we doing an x64 build?" + if sdk.name != 'dota' or builder.target_platform == 'windows': + binary.sources += ['sourcehook/sourcehook_hookmangen.cpp'] nodes = builder.Add(binary) MMS.binaries += [nodes] diff --git a/core/metamod.cpp b/core/metamod.cpp index d283c4b..c93196c 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -131,7 +131,9 @@ static ConVar *mm_basedir = NULL; static CreateInterfaceFn engine_factory = NULL; static CreateInterfaceFn physics_factory = NULL; static CreateInterfaceFn filesystem_factory = NULL; +#if !defined( __amd64__ ) static CHookManagerAutoGen g_SH_HookManagerAutoGen(&g_SourceHook); +#endif static META_RES last_meta_res; static IServerPluginCallbacks *vsp_callbacks = NULL; static bool were_plugins_loaded = false; @@ -1025,11 +1027,19 @@ void *MetamodSource::MetaFactory(const char *iface, int *ret, PluginId *id) } else if (strcmp(iface, MMIFACE_SH_HOOKMANAUTOGEN) == 0) { +#if defined( __amd64__ ) + if (ret) + { + *ret = META_IFACE_FAILED; + } + return nullptr; +#else if (ret) { *ret = META_IFACE_OK; } return static_cast(static_cast(&g_SH_HookManagerAutoGen)); +#endif } CPluginManager::CPlugin *pl; From a88de796a3b2dbc09dddbb8ca490ccc37e92468d Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 14:01:34 -0400 Subject: [PATCH 25/44] Build Dota core and loader + versionlib as 64-bit. TODO: we need both x86 and x64 of versionlib and loader. --- AMBuildScript | 7 +++++++ core/metamod_oslink.h | 4 ---- loader/AMBuilder | 5 +++++ versionlib/AMBuildScript | 7 +++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 57486ed..f3dca68 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -280,6 +280,13 @@ class MMSConfig(object): else: compiler.defines += ['COMPILER_GCC'] + if sdk.name == 'dota' and builder.target_platform in ['linux', 'mac']: + compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] + compiler.cflags.remove('-m32') + compiler.cflags += ['-m64', '-fPIC'] + compiler.linkflags.remove('-m32') + compiler.linkflags += ['-m64'] + if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: if builder.target_platform in ['linux', 'mac']: compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] diff --git a/core/metamod_oslink.h b/core/metamod_oslink.h index 03b6764..8a697d4 100644 --- a/core/metamod_oslink.h +++ b/core/metamod_oslink.h @@ -104,10 +104,6 @@ bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength); typedef unsigned __int32 uint32_t; #elif defined __GNUC__ #include -#if !__GLIBC_HAVE_LONG_LONG - typedef long long int64_t; - typedef unsigned long long uint64_t; -#endif #endif #if !defined __linux__ && !defined __APPLE__ diff --git a/loader/AMBuilder b/loader/AMBuilder index 0207359..6c73ecc 100644 --- a/loader/AMBuilder +++ b/loader/AMBuilder @@ -13,6 +13,11 @@ def configure_library(name, linux_defines): if builder.target_platform == 'linux': binary.compiler.defines += linux_defines + # Temporary Source2 hack. Always build linux with -m64 + binary.compiler.cflags.remove('-m32') + binary.compiler.cflags += ['-m64', '-fPIC'] + binary.compiler.linkflags.remove('-m32') + binary.compiler.linkflags += ['-m64'] nodes = builder.Add(binary) MMS.binaries += [nodes] diff --git a/versionlib/AMBuildScript b/versionlib/AMBuildScript index d46d66e..432c2fe 100644 --- a/versionlib/AMBuildScript +++ b/versionlib/AMBuildScript @@ -6,6 +6,13 @@ lib.compiler.sourcedeps += MMS.generated_headers lib.sources += [ 'versionlib.cpp' ] + +# Temporary Source2 hack. Always build linux with -m64 +if builder.target_platform == 'linux': + lib.compiler.cflags.remove('-m32') + lib.compiler.cflags += ['-m64', '-fPIC'] + + cmd = builder.Add(lib) rvalue = cmd.binary From a2400e36819ce1b4c4adac8046300cdf3eabbe3c Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 14:02:37 -0400 Subject: [PATCH 26/44] Change AllowDedicatedServer hook to be Windows-only. It's not needed elsewhere right now. --- core/provider/provider_ep2.cpp | 4 ++-- core/provider/provider_ep2.h | 2 +- loader/gamedll.cpp | 12 ++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 3a0337f..2f69607 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -43,7 +43,7 @@ #include #endif -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 ) SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); bool BaseProvider::AllowDedicatedServers(EUniverse universe) const { @@ -239,7 +239,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, gameclients, ClientCommand, false); } -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 ) SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &BaseProvider::AllowDedicatedServers), false); #endif } diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index fe46da6..dea6c4e 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -81,7 +81,7 @@ public: virtual const char *GetUserMessage(int index, int *size=NULL); virtual int DetermineSourceEngine(); virtual bool ProcessVDF(const char *file, char path[], size_t path_len, char alias[], size_t alias_len); -#if SOURCE_ENGINE == SE_DOTA +#if SOURCE_ENGINE == SE_DOTA && defined( _WIN32 ) bool AllowDedicatedServers(EUniverse universe) const; #endif }; diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 2726e1a..e46bc83 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -52,7 +52,9 @@ static ISource2ServerConfig *config_iface = NULL; static QueryValveInterface gamedll_qvi = NULL; static int gamedll_version = 0; static int isgd_shutdown_index = -1; +#if defined _WIN32 static int is2sc_allowdedi_index = 21; +#endif static char mm_path[PLATFORM_MAX_PATH]; static bool g_is_source2 = false; @@ -229,15 +231,19 @@ mm_PatchDllInit(bool patch); static void mm_PatchDllShutdown(); +#if defined _WIN32 static void mm_PatchAllowDedicated(bool patch); +#endif static void mm_PatchConnect(bool patch); static void *isgd_orig_init = NULL; static void *isgd_orig_shutdown = NULL; +#if defined _WIN32 static void *is2sc_orig_allowdedi = NULL; +#endif static void *is2sc_orig_connect = NULL; class VEmptyClass @@ -299,11 +305,13 @@ public: return result; } +#if defined _WIN32 virtual bool AllowDedicatedServers(int universe) const { mm_PatchAllowDedicated(false); return true; } +#endif }; class ISource2Server @@ -661,6 +669,7 @@ mm_PatchDllShutdown() vtable_dest[isgd_shutdown_index] = vtable_src[mfp.vtblindex]; } +#if defined _WIN32 static void mm_PatchAllowDedicated(bool patch) { @@ -694,6 +703,7 @@ mm_PatchAllowDedicated(bool patch) is2sc_orig_allowdedi = NULL; } } +#endif static void mm_PatchConnect(bool patch) @@ -776,7 +786,9 @@ mm_GameDllRequest(const char *name, int *ret) gamedll_qvi = qvi; mm_PatchConnect(true); +#if defined _WIN32 mm_PatchAllowDedicated(true); +#endif if (ret != NULL) *ret = 0; From 18bdaf4732ab9bc31618891dfc82aa3e1bbf8c87 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 14:03:21 -0400 Subject: [PATCH 27/44] Hack to account for Dota server bin name being "libserver". --- loader/gamedll.cpp | 5 ++++- loader/loader.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index e46bc83..60a3d3e 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -73,10 +73,13 @@ static bool g_is_source2 = false; #define PLATFORM_NAME "osx32" #endif #elif defined __linux__ -#define SERVER_NAME "server" LIB_SUFFIX #if defined __amd64__ +// hackhack - source2 uses libserver as name on POSIX, but source1 x64 does not +// (but source1 x64 is also client-only right now so what-ev) +#define SERVER_NAME "libserver" LIB_SUFFIX #define PLATFORM_NAME "linuxsteamrt64" #else +#define SERVER_NAME "server" LIB_SUFFIX #define PLATFORM_NAME "linuxsteamrt32" #endif #endif diff --git a/loader/loader.cpp b/loader/loader.cpp index e768e01..7b16657 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -114,7 +114,12 @@ mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength) return false; len = strlen(mm_path); - temp_len = strlen("server" LIBRARY_EXT); + + const char *pLastSlash = strrchr(mm_path, PATH_SEP_CHAR); + if (!pLastSlash) + return false; + + temp_len = strlen(&pLastSlash[1]); if (len < temp_len) return false; From 878f7531fb1f99699a725d482e0983c867c3a2b9 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 14:04:02 -0400 Subject: [PATCH 28/44] Fix a few unrelated compile warnings. --- core/provider/provider_ep2.cpp | 4 ++-- loader/gamedll.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 2f69607..6ccdef3 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -189,7 +189,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, char searchPath[260]; baseFs->GetSearchPath("GAME", (GetSearchPathTypes_t)0, searchPath, sizeof(searchPath)); - for (int i = 0; i < sizeof(searchPath); ++i) + for (size_t i = 0; i < sizeof(searchPath); ++i) { if (searchPath[i] == ';') { @@ -206,7 +206,7 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, baseFs->RemoveSearchPaths("DEFAULT_WRITE_PATH"); baseFs->GetSearchPath("GAME", (GetSearchPathTypes_t)0, searchPath, sizeof(searchPath)); - for (int i = 0; i < sizeof(searchPath); ++i) + for (size_t i = 0; i < sizeof(searchPath); ++i) { if (searchPath[i] == ';') { diff --git a/loader/gamedll.cpp b/loader/gamedll.cpp index 60a3d3e..b110a12 100644 --- a/loader/gamedll.cpp +++ b/loader/gamedll.cpp @@ -165,8 +165,8 @@ mm_DetectGameInformation() lptr = cur_path; } - char *pRelPath = is_source2 ? "../../" : ""; - char *pOSDir = is_source2 ? PLATFORM_NAME "/" : ""; + const char *pRelPath = is_source2 ? "../../" : ""; + const char *pOSDir = is_source2 ? PLATFORM_NAME "/" : ""; if (stricmp(key, "GameBin") == 0) mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s%s/%s" SERVER_NAME, lptr, pRelPath, ptr, pOSDir); else if (!ptr[0]) From 314e116927c89354928e3b91fe957475d5b0346b Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Fri, 22 Jul 2016 15:39:14 -0400 Subject: [PATCH 29/44] Remove old Source1 Dota detection. Not used anymore. --- loader/loader.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/loader/loader.cpp b/loader/loader.cpp index 7b16657..785de41 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -281,11 +281,7 @@ mm_GetGameName(char *buffer, size_t size) MetamodBackend mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serverFactory, const char *game_name) { - if (engineFactory("VEngineServer024", NULL) != NULL) - { - return MMBackend_DOTA; - } - else if (engineFactory("VEngineServer023", NULL) != NULL) + if (engineFactory("VEngineServer023", NULL) != NULL) { if (engineFactory("EngineTraceServer004", NULL) == NULL) { From 0eaf14f9ecfe006c6fe0224e331858b7af4fa99a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 23 Jul 2016 18:39:12 -0700 Subject: [PATCH 30/44] Update configure.py and buildscripts to AMBuild API v2.1. --- AMBuildScript | 146 ++++++++++++++++++++------------------- configure.py | 16 ++--- core/AMBuilder | 2 +- loader/AMBuilder | 4 +- versionlib/AMBuildScript | 4 +- 5 files changed, 89 insertions(+), 83 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index f3dca68..8b5741e 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -8,9 +8,14 @@ class SDK(object): self.ext = ext self.code = aDef self.define = name - self.platform = platform self.name = dir self.path = None # Actual path + self.platformSpec = platform + + def shouldBuild(self, target): + if target.platform not in self.platformSpec: + return False + return True WinOnly = ['windows'] WinLinux = ['windows', 'linux'] @@ -92,7 +97,7 @@ class MMSConfig(object): for sdk_name in PossibleSDKs: sdk = PossibleSDKs[sdk_name] - if builder.target_platform in sdk.platform: + if sdk.shouldBuild(builder.target): if builder.options.hl2sdk_root: sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder) else: @@ -111,11 +116,10 @@ class MMSConfig(object): def configure(self): builder.AddConfigureFile('pushbuild.txt') - cfg = builder.DetectCompilers() - cxx = cfg.cxx + cxx = builder.DetectCxx() if cxx.behavior == 'gcc': - cfg.defines += [ + cxx.defines += [ 'stricmp=strcasecmp', '_stricmp=strcasecmp', '_snprintf=snprintf', @@ -123,7 +127,7 @@ class MMSConfig(object): 'HAVE_STDINT_H', 'GNUC', ] - cfg.cflags += [ + cxx.cflags += [ '-pipe', '-fno-strict-aliasing', '-Wall', @@ -134,47 +138,49 @@ class MMSConfig(object): '-msse', '-m32', ] - cfg.cxxflags += [ '-std=c++11' ] - if (cxx.name == 'gcc' and cxx.majorVersion >= 4) or cxx.name == 'clang': - cfg.cflags += ['-fvisibility=hidden'] - cfg.cxxflags += ['-fvisibility-inlines-hidden'] - cfg.linkflags += ['-m32'] - cfg.cxxflags += [ + cxx.cxxflags += [ '-std=c++11' ] + if (cxx.version >= 'gcc-4.0') or cxx.family == 'clang': + cxx.cflags += ['-fvisibility=hidden'] + cxx.cxxflags += ['-fvisibility-inlines-hidden'] + cxx.linkflags += ['-m32'] + cxx.cxxflags += [ '-fno-exceptions', '-fno-rtti', '-fno-threadsafe-statics', '-Wno-non-virtual-dtor', '-Wno-overloaded-virtual', ] - if (cxx.name == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \ - (cxx.name == 'clang' and cxx.majorVersion >= 3): - cfg.cxxflags += ['-Wno-delete-non-virtual-dtor'] - if cxx.name == 'gcc': - cfg.cflags += ['-mfpmath=sse'] - if cxx.name == 'clang': - cfg.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] - if cfg.version >= 'apple-clang-5.1' or cfg.version >= 'clang-3.4': - cfg.cxxflags += ['-Wno-deprecated-register'] + if (cxx.version >= 'gcc-4.7' or cxx.version >= 'clang-3.0'): + cxx.cxxflags += ['-Wno-delete-non-virtual-dtor'] + if cxx.family == 'gcc': + cxx.cflags += ['-mfpmath=sse'] + if cxx.family == 'clang': + cxx.cxxflags += [ + '-Wno-implicit-exception-spec-mismatch', + '-Wno-inconsistent-missing-override', + ] + if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4': + cxx.cxxflags += ['-Wno-deprecated-register'] else: - cfg.cxxflags += ['-Wno-deprecated'] + cxx.cxxflags += ['-Wno-deprecated'] elif cxx.name == 'msvc': if builder.options.debug == '1': - cfg.cflags += ['/MTd'] - cfg.linkflags += ['/NODEFAULTLIB:libcmt'] + cxx.cflags += ['/MTd'] + cxx.linkflags += ['/NODEFAULTLIB:libcmt'] else: - cfg.cflags += ['/MT'] - cfg.defines += [ + cxx.cflags += ['/MT'] + cxx.defines += [ '_CRT_SECURE_NO_DEPRECATE', '_CRT_SECURE_NO_WARNINGS', '_CRT_NONSTDC_NO_DEPRECATE', ] - cfg.cflags += [ + cxx.cflags += [ '/W3', '/Zi', ] - cfg.cxxflags += ['/TP'] - cfg.linkflags += [ + cxx.cxxflags += ['/TP'] + cxx.linkflags += [ '/MACHINE:X86', '/SUBSYSTEM:WINDOWS', 'kernel32.lib', @@ -193,58 +199,58 @@ class MMSConfig(object): # Optimization if builder.options.opt == '1': - cfg.defines += ['NDEBUG'] + cxx.defines += ['NDEBUG'] if cxx.behavior == 'gcc': - cfg.cflags += ['-O3'] + cxx.cflags += ['-O3'] elif cxx.behavior == 'msvc': - cfg.cflags += ['/Ox', '/Zo'] - cfg.linkflags += ['/OPT:ICF', '/OPT:REF'] + cxx.cflags += ['/Ox', '/Zo'] + cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] # Debugging if builder.options.debug == '1': - cfg.defines += ['DEBUG', '_DEBUG'] + cxx.defines += ['DEBUG', '_DEBUG'] if cxx.behavior == 'gcc': - cfg.cflags += ['-g3'] + cxx.cflags += ['-g3'] elif cxx.behavior == 'msvc': - cfg.cflags += ['/Od', '/RTC1'] + cxx.cflags += ['/Od', '/RTC1'] # This needs to be after our optimization flags which could otherwise disable it. - if cxx.name == 'msvc': + if cxx.family == 'msvc': # Don't omit the frame pointer. - cfg.cflags += ['/Oy-'] + cxx.cflags += ['/Oy-'] # Platform-specifics - if builder.target_platform == 'linux': - cfg.defines += ['_LINUX', 'POSIX'] - if cxx.name == 'gcc': - cfg.linkflags += ['-static-libgcc'] - elif cxx.name == 'clang': - cfg.linkflags += ['-lgcc_eh'] + if builder.target.platform == 'linux': + cxx.defines += ['_LINUX', 'POSIX'] + if cxx.family == 'gcc': + cxx.linkflags += ['-static-libgcc'] + elif cxx.family == 'clang': + cxx.linkflags += ['-lgcc_eh'] elif builder.target_platform == 'mac': - cfg.defines += ['OSX', '_OSX', 'POSIX'] - cfg.cflags += ['-mmacosx-version-min=10.5'] - cfg.linkflags += [ + cxx.defines += ['OSX', '_OSX', 'POSIX'] + cxx.cflags += ['-mmacosx-version-min=10.5'] + cxx.linkflags += [ '-mmacosx-version-min=10.5', '-arch', 'i386', '-lstdc++', ] elif builder.target_platform == 'windows': - cfg.defines += ['WIN32', '_WINDOWS'] + cxx.defines += ['WIN32', '_WINDOWS'] # Finish up. - cfg.defines += [ 'MMS_USE_VERSIONLIB' ] - cfg.includes += [ + cxx.defines += [ 'MMS_USE_VERSIONLIB' ] + cxx.includes += [ os.path.join(builder.sourcePath, 'public'), ] if self.use_auto_versioning(): - cfg.defines += ['MMS_GENERATED_BUILD'] - cfg.includes += [ + cxx.defines += ['MMS_GENERATED_BUILD'] + cxx.includes += [ os.path.join(builder.buildPath, 'includes'), os.path.join(builder.sourcePath, 'versionlib'), ] def HL2Compiler(self, context, sdk): - compiler = context.compiler.clone() + compiler = context.cxx.clone() compiler.cxxincludes += [ os.path.join(context.currentSourcePath), os.path.join(context.currentSourcePath, 'sourcehook'), @@ -268,19 +274,19 @@ class MMSConfig(object): compiler.defines += ['SOURCE_ENGINE=' + sdk.code] - if sdk.name in ['sdk2013', 'bms'] and compiler.cxx.behavior == 'gcc': + if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'): # The 2013 SDK already has these in public/tier0/basetypes.h compiler.defines.remove('stricmp=strcasecmp') compiler.defines.remove('_stricmp=strcasecmp') compiler.defines.remove('_snprintf=snprintf') compiler.defines.remove('_vsnprintf=vsnprintf') - if compiler.cc.behavior == 'msvc': + if compiler.family == 'msvc': compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32'] else: compiler.defines += ['COMPILER_GCC'] - if sdk.name == 'dota' and builder.target_platform in ['linux', 'mac']: + if sdk.name == 'dota' and builder.target.platform in ['linux', 'mac']: compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] compiler.cflags.remove('-m32') compiler.cflags += ['-m64', '-fPIC'] @@ -288,10 +294,10 @@ class MMSConfig(object): compiler.linkflags += ['-m64'] if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: - if builder.target_platform in ['linux', 'mac']: + if builder.target.platform in ['linux', 'mac']: compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] - if sdk.name == 'csgo' and builder.target_platform == 'linux': + if sdk.name == 'csgo' and builder.target.platform == 'linux': compiler.linkflags += ['-lstdc++'] @@ -301,13 +307,13 @@ class MMSConfig(object): return compiler def AddVersioning(self, binary): - if builder.target_platform == 'windows': + if builder.target.platform == 'windows': binary.sources += ['version.rc'] binary.compiler.rcdefines += [ 'BINARY_NAME="{0}"'.format(binary.outputFile), 'RC_COMPILE' ] - elif builder.target_platform == 'mac': + elif builder.target.platform == 'mac': binary.compiler.postlink += [ '-compatibility_version', '1.0.0', '-current_version', self.productVersion @@ -334,17 +340,17 @@ class MMSConfig(object): return binary def Library(self, context, name): - compiler = context.compiler.clone() + compiler = context.cxx.clone() return self.LibraryBuilder(compiler, name) def Program(self, context, name): - compiler = context.compiler.clone() + compiler = context.cxx.clone() return self.ProgramBuilder(compiler, name) def HL2Library(self, context, name, sdk): compiler = self.HL2Compiler(context, sdk) - if builder.target_platform == 'linux': + if builder.target.platform == 'linux': if sdk.name == 'episode1': lib_folder = os.path.join(sdk.path, 'linux_sdk') elif sdk.name in ['sdk2013', 'bms']: @@ -357,7 +363,7 @@ class MMSConfig(object): else: lib_folder = os.path.join(sdk.path, 'lib', 'mac') - if builder.target_platform in ['linux', 'mac']: + if builder.target.platform in ['linux', 'mac']: if sdk.name in ['sdk2013', 'bms']: compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'tier1.a'))] else: @@ -369,7 +375,7 @@ class MMSConfig(object): binary = self.LibraryBuilder(compiler, name) dynamic_libs = [] - if builder.target_platform == 'linux': + if builder.target.platform == 'linux': compiler.linkflags[0:0] = ['-lm'] if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency']: dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] @@ -377,10 +383,10 @@ class MMSConfig(object): dynamic_libs = ['libtier0.so', 'libvstdlib.so'] else: dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] - elif builder.target_platform == 'mac': + elif builder.target.platform == 'mac': binary.compiler.linkflags.append('-liconv') dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] - elif builder.target_platform == 'windows': + elif builder.target.platform == 'windows': libs = ['tier0', 'tier1', 'vstdlib'] if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']: libs.append('interfaces') @@ -409,11 +415,11 @@ MMS.detectSDKs() MMS.configure() if MMS.use_auto_versioning(): - MMS.generated_headers = builder.RunScript( + MMS.generated_headers = builder.Build( 'support/buildbot/Versioning', { 'MMS': MMS } ) - MMS.versionlib = builder.RunScript( + MMS.versionlib = builder.Build( 'versionlib/AMBuildScript', { 'MMS': MMS } ) @@ -434,5 +440,5 @@ if builder.backend == 'amb2': 'support/buildbot/PackageScript', ] -builder.RunBuildScripts(BuildScripts, { 'MMS': MMS }) +builder.Build(BuildScripts, { 'MMS': MMS }) diff --git a/configure.py b/configure.py index 6b157b2..4be3fab 100644 --- a/configure.py +++ b/configure.py @@ -12,17 +12,17 @@ except: sys.stderr.write('http://www.alliedmods.net/ambuild\n') sys.exit(1) -run = run.PrepareBuild(sourcePath=sys.path[0]) -run.default_build_folder = 'obj-' + run.target_platform -run.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, +parser = run.BuildParser(sourcePath=sys.path[0], api='2.1') +parser.default_build_folder = 'obj-' + parser.host.platform +parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, help='Root search folder for HL2SDKs') -run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', +parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', help='Enable debugging symbols') -run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', +parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', help='Enable optimization') -run.options.add_option('-s', '--sdks', default='all', dest='sdks', +parser.options.add_option('-s', '--sdks', default='all', dest='sdks', help='Build against specified SDKs; valid args are "all", "present", or ' 'comma-delimited list of engine names (default: %default)') -run.options.add_option('--enable-tests', default=False, dest='enable_tests', action='store_true', +parser.options.add_option('--enable-tests', default=False, dest='enable_tests', action='store_true', help='Build tests.') -run.Configure() +parser.Configure() diff --git a/core/AMBuilder b/core/AMBuilder index 00d8f54..cb29f3d 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -27,7 +27,7 @@ for sdk_name in MMS.sdks: ] # Source2 hack. TODO: check this more deterministically, "are we doing an x64 build?" - if sdk.name != 'dota' or builder.target_platform == 'windows': + if sdk.name != 'dota' or builder.target.platform == 'windows': binary.sources += ['sourcehook/sourcehook_hookmangen.cpp'] nodes = builder.Add(binary) MMS.binaries += [nodes] diff --git a/loader/AMBuilder b/loader/AMBuilder index 6c73ecc..88abec0 100644 --- a/loader/AMBuilder +++ b/loader/AMBuilder @@ -11,7 +11,7 @@ def configure_library(name, linux_defines): 'utility.cpp', ] - if builder.target_platform == 'linux': + if builder.target.platform == 'linux': binary.compiler.defines += linux_defines # Temporary Source2 hack. Always build linux with -m64 binary.compiler.cflags.remove('-m32') @@ -23,5 +23,5 @@ def configure_library(name, linux_defines): MMS.binaries += [nodes] configure_library('server', ['LIB_PREFIX="lib"', 'LIB_SUFFIX=".so"']) -if builder.target_platform == 'linux': +if builder.target.platform == 'linux': configure_library('server_i486', ['LIB_PREFIX=""', 'LIB_SUFFIX="_i486.so"']) diff --git a/versionlib/AMBuildScript b/versionlib/AMBuildScript index 432c2fe..cf8e4e8 100644 --- a/versionlib/AMBuildScript +++ b/versionlib/AMBuildScript @@ -1,6 +1,6 @@ # vim: sts=2 ts=8 sw=2 tw=99 et ft=python: -lib = builder.compiler.StaticLibrary("version") +lib = builder.cxx.StaticLibrary("version") lib.compiler.defines.remove('MMS_USE_VERSIONLIB') lib.compiler.sourcedeps += MMS.generated_headers lib.sources += [ @@ -8,7 +8,7 @@ lib.sources += [ ] # Temporary Source2 hack. Always build linux with -m64 -if builder.target_platform == 'linux': +if builder.target.platform == 'linux': lib.compiler.cflags.remove('-m32') lib.compiler.cflags += ['-m64', '-fPIC'] From 1b91dc28ca3996c9dcb2ebae4e48dea5766dac81 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 23 Jul 2016 19:29:56 -0700 Subject: [PATCH 31/44] Add --target-arch support. --- AMBuildScript | 37 ++++++++++++++++++++++++++++--------- configure.py | 6 +++++- loader/AMBuilder | 14 +++++++------- versionlib/AMBuildScript | 6 ------ 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 8b5741e..e130b99 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -12,14 +12,26 @@ class SDK(object): self.path = None # Actual path self.platformSpec = platform + # By default, nothing supports x64. + if type(platform) is list: + self.platformSpec = {p: ['x86'] for p in platform} + else: + self.platformSpec = platform + def shouldBuild(self, target): if target.platform not in self.platformSpec: return False + if target.arch not in self.platformSpec[target.platform]: + return False return True WinOnly = ['windows'] WinLinux = ['windows', 'linux'] WinLinuxMac = ['windows', 'linux', 'mac'] +Source2 = { + 'windows': ['x86', 'x86_64'], + 'linux': ['x86_64'], +} PossibleSDKs = { 'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'), @@ -37,7 +49,7 @@ PossibleSDKs = { 'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'), 'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'), 'csgo': SDK('HL2SDKCSGO', '2.csgo', '20', 'CSGO', WinLinuxMac, 'csgo'), - 'dota': SDK('HL2SDKDOTA', '2.dota', '21', 'DOTA', WinLinux, 'dota'), + 'dota': SDK('HL2SDKDOTA', '2.dota', '21', 'DOTA', Source2, 'dota'), 'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'), 'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'), 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), @@ -111,11 +123,15 @@ class MMSConfig(object): self.sdks[sdk_name] = sdk if len(self.sdks) < 1 and len(sdk_list): - raise Exception('At least one SDK must be available.') + raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format( + builder.target.platform, builder.target.arch)) def configure(self): builder.AddConfigureFile('pushbuild.txt') + if builder.target.arch not in ['x86', 'x86_64']: + raise Exception('Unknown target architecture: {0}'.format(builder.target.arch)) + cxx = builder.DetectCxx() if cxx.behavior == 'gcc': @@ -136,13 +152,19 @@ class MMSConfig(object): '-Wno-unused', '-Wno-switch', '-msse', - '-m32', ] + + if builder.target.arch == 'x86': + cxx.cflags += ['-m32'] + cxx.linkflags += ['-m32'] + elif builder.target.arch == 'x86_64': + cxx.cflags += ['-m64', '-fPIC'] + cxx.linkflags += ['-m64'] + cxx.cxxflags += [ '-std=c++11' ] if (cxx.version >= 'gcc-4.0') or cxx.family == 'clang': cxx.cflags += ['-fvisibility=hidden'] cxx.cxxflags += ['-fvisibility-inlines-hidden'] - cxx.linkflags += ['-m32'] cxx.cxxflags += [ '-fno-exceptions', '-fno-rtti', @@ -287,11 +309,8 @@ class MMSConfig(object): compiler.defines += ['COMPILER_GCC'] if sdk.name == 'dota' and builder.target.platform in ['linux', 'mac']: - compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] - compiler.cflags.remove('-m32') - compiler.cflags += ['-m64', '-fPIC'] - compiler.linkflags.remove('-m32') - compiler.linkflags += ['-m64'] + if builder.target.arch == 'x86_64': + compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: if builder.target.platform in ['linux', 'mac']: diff --git a/configure.py b/configure.py index 4be3fab..4f31397 100644 --- a/configure.py +++ b/configure.py @@ -12,8 +12,12 @@ except: sys.stderr.write('http://www.alliedmods.net/ambuild\n') sys.exit(1) +def make_objdir_name(p): + return 'obj-linux-' + p.target_arch + parser = run.BuildParser(sourcePath=sys.path[0], api='2.1') -parser.default_build_folder = 'obj-' + parser.host.platform +parser.default_arch = 'x86' +parser.default_build_folder = make_objdir_name parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, help='Root search folder for HL2SDKs') parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', diff --git a/loader/AMBuilder b/loader/AMBuilder index 88abec0..c2f30aa 100644 --- a/loader/AMBuilder +++ b/loader/AMBuilder @@ -13,15 +13,15 @@ def configure_library(name, linux_defines): if builder.target.platform == 'linux': binary.compiler.defines += linux_defines - # Temporary Source2 hack. Always build linux with -m64 - binary.compiler.cflags.remove('-m32') - binary.compiler.cflags += ['-m64', '-fPIC'] - binary.compiler.linkflags.remove('-m32') - binary.compiler.linkflags += ['-m64'] nodes = builder.Add(binary) MMS.binaries += [nodes] -configure_library('server', ['LIB_PREFIX="lib"', 'LIB_SUFFIX=".so"']) -if builder.target.platform == 'linux': +libname = 'server' +if builder.target.platform == 'linux' and builder.target.arch == 'x86_64': + libname = 'libserver' + +configure_library(libname, ['LIB_PREFIX="lib"', 'LIB_SUFFIX=".so"']) + +if builder.target.platform == 'linux' and builder.target.arch == 'x86': configure_library('server_i486', ['LIB_PREFIX=""', 'LIB_SUFFIX="_i486.so"']) diff --git a/versionlib/AMBuildScript b/versionlib/AMBuildScript index cf8e4e8..fb45d8e 100644 --- a/versionlib/AMBuildScript +++ b/versionlib/AMBuildScript @@ -7,12 +7,6 @@ lib.sources += [ 'versionlib.cpp' ] -# Temporary Source2 hack. Always build linux with -m64 -if builder.target.platform == 'linux': - lib.compiler.cflags.remove('-m32') - lib.compiler.cflags += ['-m64', '-fPIC'] - - cmd = builder.Add(lib) rvalue = cmd.binary From 4104721ce233cd8b094c527e0c4393a7a83ffb08 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sun, 24 Jul 2016 14:12:52 -0400 Subject: [PATCH 32/44] More changes for AMBuild 2.1 api. --- AMBuildScript | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index e130b99..5ef6c49 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -186,7 +186,7 @@ class MMSConfig(object): else: cxx.cxxflags += ['-Wno-deprecated'] - elif cxx.name == 'msvc': + elif cxx.like('msvc'): if builder.options.debug == '1': cxx.cflags += ['/MTd'] cxx.linkflags += ['/NODEFAULTLIB:libcmt'] @@ -248,7 +248,7 @@ class MMSConfig(object): cxx.linkflags += ['-static-libgcc'] elif cxx.family == 'clang': cxx.linkflags += ['-lgcc_eh'] - elif builder.target_platform == 'mac': + elif builder.target.platform == 'mac': cxx.defines += ['OSX', '_OSX', 'POSIX'] cxx.cflags += ['-mmacosx-version-min=10.5'] cxx.linkflags += [ @@ -256,7 +256,7 @@ class MMSConfig(object): '-arch', 'i386', '-lstdc++', ] - elif builder.target_platform == 'windows': + elif builder.target.platform == 'windows': cxx.defines += ['WIN32', '_WINDOWS'] # Finish up. @@ -376,7 +376,7 @@ class MMSConfig(object): lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32') else: lib_folder = os.path.join(sdk.path, 'lib', 'linux') - elif builder.target_platform == 'mac': + elif builder.target.platform == 'mac': if sdk.name in ['sdk2013', 'bms']: lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32') else: From a779cb9b76a10e8f98df04323de7395e7dacb798 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sun, 24 Jul 2016 15:24:00 -0400 Subject: [PATCH 33/44] Enable 64-bit defines for WIndows x86_64 builds. --- AMBuildScript | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 5ef6c49..5a1d5bc 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -304,13 +304,16 @@ class MMSConfig(object): compiler.defines.remove('_vsnprintf=vsnprintf') if compiler.family == 'msvc': - compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32'] + compiler.defines += ['COMPILER_MSVC'] + if builder.target.arch == 'x86': + compiler.defines += ['COMPILER_MSVC32'] + elif builder.target.arch == 'x86_64': + compiler.defines += ['COMPILER_MSVC64'] else: compiler.defines += ['COMPILER_GCC'] - if sdk.name == 'dota' and builder.target.platform in ['linux', 'mac']: - if builder.target.arch == 'x86_64': - compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] + if sdk.name == 'dota' and builder.target.arch == 'x86_64': + compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'dota']: if builder.target.platform in ['linux', 'mac']: From eeef0b5c0c63a4623131d79ff60c8dc23577642b Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Tue, 26 Jul 2016 10:51:13 -0400 Subject: [PATCH 34/44] Fix linker flags and lib paths on Win64. --- AMBuildScript | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 5a1d5bc..eae7458 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -202,8 +202,13 @@ class MMSConfig(object): '/Zi', ] cxx.cxxflags += ['/TP'] + + if builder.target.arch == 'x86': + cxx.linkflags += ['/MACHINE:X86'] + elif builder.target.arch == 'x86_64': + cxx.linkflags += ['/MACHINE:X64'] + cxx.linkflags += [ - '/MACHINE:X86', '/SUBSYSTEM:WINDOWS', 'kernel32.lib', 'user32.lib', @@ -217,7 +222,7 @@ class MMSConfig(object): 'uuid.lib', 'odbc32.lib', 'odbccp32.lib', - ] + ] # Optimization if builder.options.opt == '1': @@ -413,7 +418,10 @@ class MMSConfig(object): if sdk.name in ['swarm', 'blade', 'insurgency', 'csgo', 'dota']: libs.append('interfaces') for lib in libs: - lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' + if builder.target.arch == 'x86': + lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' + elif builder.target.arch == 'x86_64': + lib_path = os.path.join(sdk.path, 'lib', 'public', 'win64', lib) + '.lib' binary.compiler.linkflags.append(binary.Dep(lib_path)) for library in dynamic_libs: From 2785cd2573ef785237e7a8f99be13ed950a1c77f Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 29 Aug 2016 19:13:07 -0400 Subject: [PATCH 35/44] Update for StartChangeLevel prototype change. --- core/metamod.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index c93196c..5b0d6b1 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -57,7 +57,7 @@ class GameSessionConfiguration_t { }; SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); -SH_DECL_MANUALHOOK0(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *); +SH_DECL_MANUALHOOK1(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, int); SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); @@ -77,7 +77,7 @@ static void Handler_Init(GameSessionConfiguration_t *, const char *); static CUtlVector * -Handler_StartChangeLevel(); +Handler_StartChangeLevel(int unknown); #else SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -684,7 +684,7 @@ Handler_Init(GameSessionConfiguration_t *pConfig, const char *pszMapName) } static CUtlVector * -Handler_StartChangeLevel() +Handler_StartChangeLevel(int unknown) { mm_HandleLevelShutdown(); From 9a8ebe74ffc24929bde1f3763287355e67507dda Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 10 Oct 2016 14:54:54 -0400 Subject: [PATCH 36/44] Update for StartChangeLevel prototype change, again. --- core/metamod.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 5b0d6b1..8121d15 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -57,7 +57,7 @@ class GameSessionConfiguration_t { }; SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); -SH_DECL_MANUALHOOK1(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, int); +SH_DECL_MANUALHOOK2(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, const char *, void *); SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); @@ -77,7 +77,7 @@ static void Handler_Init(GameSessionConfiguration_t *, const char *); static CUtlVector * -Handler_StartChangeLevel(int unknown); +Handler_StartChangeLevel(const char *, void *); #else SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -684,7 +684,7 @@ Handler_Init(GameSessionConfiguration_t *pConfig, const char *pszMapName) } static CUtlVector * -Handler_StartChangeLevel(int unknown) +Handler_StartChangeLevel(const char *, void *) { mm_HandleLevelShutdown(); From 3eb98bd1c3bd7441fc4b9befb3dc111a1eddcf8b Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 18 Feb 2017 10:23:20 -0500 Subject: [PATCH 37/44] [Dota] Fix for new param added in INetworkGameServer::StartChangeLevel. --- core/metamod.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 8121d15..4f85537 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -57,7 +57,7 @@ class GameSessionConfiguration_t { }; SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); -SH_DECL_MANUALHOOK2(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, const char *, void *); +SH_DECL_MANUALHOOK3(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, const char *, const char *, void *); SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); @@ -77,7 +77,7 @@ static void Handler_Init(GameSessionConfiguration_t *, const char *); static CUtlVector * -Handler_StartChangeLevel(const char *, void *); +Handler_StartChangeLevel(const char *, const char *, void *); #else SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); @@ -684,7 +684,7 @@ Handler_Init(GameSessionConfiguration_t *pConfig, const char *pszMapName) } static CUtlVector * -Handler_StartChangeLevel(const char *, void *) +Handler_StartChangeLevel(const char *, const char *, void *) { mm_HandleLevelShutdown(); From b070ac2f6bdf89729074ac8f64ff2c976bd432be Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 18 Feb 2017 10:23:59 -0500 Subject: [PATCH 38/44] [Dota] Fix for getting INetworkGameServer after factory removal. --- core/metamod.cpp | 40 +++++----------------------------- core/metamod_provider.h | 1 - core/provider/provider_ep2.cpp | 10 ++++++--- 3 files changed, 12 insertions(+), 39 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 4f85537..67679ba 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -55,23 +55,16 @@ using namespace SourceHook::Impl; // (we have class structure but it requires protobuf which we don't want to include here) class GameSessionConfiguration_t { }; -SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); +SH_DECL_MANUALHOOK3_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, ISource2WorldSession *, const char *); SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); SH_DECL_MANUALHOOK3(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *, const char *, const char *, void *); SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); -SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); - -static INetworkGameServer * -Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *); static void Handler_SwitchToLoop(const char *, KeyValues *, uint32, const char *, bool); static void -Handler_StartupServer(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); - -static void -Handler_StartupServer_Post(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); +Handler_StartupServer_Post(const GameSessionConfiguration_t &, ISource2WorldSession *, const char *); static void Handler_Init(GameSessionConfiguration_t *, const char *); @@ -199,7 +192,6 @@ mm_InitializeForLoad() provider->DisplayError("Metamod:Source could not find a valid hook for INetworkServerService::StartupServer"); } SH_MANUALHOOK_RECONFIGURE(SGD_StartupServer, info.vtblindex, info.vtbloffs, info.thisptroffs); - SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer), false); SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer_Post), true); if (!provider->GetHookInfo(ProvidedHook_SwitchToLoop, &info)) @@ -623,34 +615,12 @@ Handler_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const } static void -Handler_StartupServer(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) -{ - SourceHook::MemFuncInfo info; - if (!provider->GetHookInfo(ProvidedHook_AllocateServer, &info)) - { - provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServerFactory::Allocate"); - } - SH_MANUALHOOK_RECONFIGURE(SGD_AllocateServer, info.vtblindex, info.vtbloffs, info.thisptroffs); - SH_ADD_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); - - RETURN_META(MRES_IGNORED); -} - -static void -Handler_StartupServer_Post(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) -{ - SH_REMOVE_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); - - RETURN_META(MRES_IGNORED); -} - -static INetworkGameServer * -Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *) +Handler_StartupServer_Post(const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *) { static bool bGameServerHooked = false; if (!bGameServerHooked) { - INetworkGameServer *netserver = META_RESULT_ORIG_RET(INetworkGameServer *); + INetworkGameServer *netserver = (META_IFACEPTR(INetworkServerService))->GetIGameServer(); SourceHook::MemFuncInfo info; if (!provider->GetHookInfo(ProvidedHook_Init, &info)) @@ -670,7 +640,7 @@ Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *) bGameServerHooked = true; } - RETURN_META_VALUE(MRES_IGNORED, nullptr); + RETURN_META(MRES_IGNORED); } static void diff --git a/core/metamod_provider.h b/core/metamod_provider.h index 408fd48..913d416 100644 --- a/core/metamod_provider.h +++ b/core/metamod_provider.h @@ -42,7 +42,6 @@ namespace SourceMM ProvidedHook_Init = 1, ProvidedHook_StartupServer = 2, ProvidedHook_SwitchToLoop = 3, - ProvidedHook_AllocateServer = 4, #else ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */ ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */ diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 6ccdef3..d5ae7ee 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -221,6 +221,10 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, g_pCVar = icvar; #endif +#if SOURCE_ENGINE == SE_DOTA + ConVar_Register(0, &g_SMConVarAccessor); +#endif + g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); CacheUserMessages(); @@ -246,6 +250,9 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, void BaseProvider::Notify_DLLShutdown_Pre() { +#if SOURCE_ENGINE == SE_DOTA + ConVar_Unregister(); +#endif g_SMConVarAccessor.RemoveMetamodCommands(); @@ -365,9 +372,6 @@ bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInf case ProvidedHook_SwitchToLoop: SourceHook::GetFuncInfo(&IEngineServiceMgr::SwitchToLoop, mfi); break; - case ProvidedHook_AllocateServer: - SourceHook::GetFuncInfo(&INetworkGameServerFactory::Allocate, mfi); - break; default: return false; } From ba7b123f87c5ba98b213fe0be667d346af7ca168 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 18 Feb 2017 14:15:07 -0500 Subject: [PATCH 39/44] Remove unintended change that snuck in with last commit. --- core/provider/provider_ep2.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index d5ae7ee..eb35c8c 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -221,10 +221,6 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, g_pCVar = icvar; #endif -#if SOURCE_ENGINE == SE_DOTA - ConVar_Register(0, &g_SMConVarAccessor); -#endif - g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); CacheUserMessages(); @@ -250,10 +246,6 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, void BaseProvider::Notify_DLLShutdown_Pre() { -#if SOURCE_ENGINE == SE_DOTA - ConVar_Unregister(); -#endif - g_SMConVarAccessor.RemoveMetamodCommands(); #if SOURCE_ENGINE == SE_DARKMESSIAH From 16a270764c122d2f8c87c40bbe1b39414f3bbdd0 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 15 Apr 2017 10:06:52 -0400 Subject: [PATCH 40/44] Use new SDK compat shim instead of ifdef for missing Error() in S2. --- core/provider/provider_ep2.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index 2430c31..54b447c 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -409,11 +409,7 @@ void BaseProvider::DisplayError(const char *fmt, ...) UTIL_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); -#if SOURCE_ENGINE == SE_DOTA - Msg("ERROR: %s", buffer); -#else Error("%s", buffer); -#endif } void BaseProvider::DisplayWarning(const char *fmt, ...) From 558a5bb446d83a61653bdc059a805b892231bcf0 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 15 Apr 2017 10:23:36 -0400 Subject: [PATCH 41/44] Restore Dark Messiah compat. --- loader/loader.cpp | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/loader/loader.cpp b/loader/loader.cpp index 029e531..ff6fa0e 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -198,6 +198,7 @@ void mm_GetGameName(char *buffer, size_t size) { buffer[0] = '\0'; + bool bHasDedicated = false; #if defined _WIN32 static char game[128]; @@ -207,15 +208,18 @@ mm_GetGameName(char *buffer, size_t size) LPWSTR *wargv = CommandLineToArgvW(pCmdLine, &argc); for (int i = 0; i < argc; ++i) { - if (wcscmp(wargv[i], L"-game") != 0) - continue; + if (wcscmp(wargv[i], L"-game") == 0) + { + if (++i >= argc) + break; - if (++i >= argc) - break; - - wcstombs(buffer, wargv[i], size); - buffer[size-1] = '\0'; - break; + wcstombs(buffer, wargv[i], size); + buffer[size-1] = '\0'; + } + else if (wcscmp(wargv[i], L"-dedicated") == 0) + { + bHasDedicated = true; + } } LocalFree(wargv); @@ -225,15 +229,18 @@ mm_GetGameName(char *buffer, size_t size) char **argv = *_NSGetArgv(); for (int i = 0; i < argc; ++i) { - if (strcmp(argv[i], "-game") != 0) - continue; + if (strcmp(argv[i], "-game") == 0) + { + if (++i >= argc) + break; - if (++i >= argc) - break; - - strncpy(buffer, argv[i], size); - buffer[size-1] = '\0'; - break; + strncpy(buffer, argv[i], size); + buffer[size-1] = '\0'; + } + else if (strcmp(argv[i], "-dedicated") == 0) + { + bHasDedicated = true; + } } #elif defined __linux__ @@ -250,13 +257,17 @@ mm_GetGameName(char *buffer, size_t size) { strncpy(buffer, arg, size); buffer[size-1] = '\0'; - break; + bNextIsGame = false; } if (strcmp(arg, "-game") == 0) { bNextIsGame = true; } + else if (strcmp(arg, "-dedicated") == 0) + { + bHasDedicated = true; + } } free(arg); @@ -268,9 +279,19 @@ mm_GetGameName(char *buffer, size_t size) if (buffer[0] == 0) { - // FIXME: this was "." and is now "dota" for Source2. - // That breaks Dark Messiah compatibility. - strncpy(buffer, "dota", size); + // HackHackHack - Different engines have different defaults if -game isn't specified + // we only use this for game detection, and not even in all cases. Old behavior was to + // give back ".", which was only really accurate for Dark Messiah. We'll add a special + // case for Source2 / Dota as well, since it only supports gameinfo loading, which relies + // on accuracy here more than VSP loading. + if (bHasDedicated) + { + strncpy(buffer, "dota", size); + } + else + { + strncpy(buffer, ".", size); + } } } From 565a18499448bd152f3438fc642e5c6c16042b82 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sun, 16 Apr 2017 16:21:02 -0400 Subject: [PATCH 42/44] Msg -> DevMsg for S2 GameInit/LevelInit/LevelShutdown messages. --- core/metamod.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 67679ba..e8508fe 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -532,7 +532,7 @@ mm_HandleGameInit() return; #if SOURCE_ENGINE == SE_DOTA - Msg("MMS: GameInit\n"); + DevMsg("MMS: GameInit\n"); #endif if (vsp_load_requested) @@ -552,7 +552,7 @@ static void mm_HandleLevelShutdown() { #if SOURCE_ENGINE == SE_DOTA - Msg("MMS: LevelShutdown\n"); + DevMsg("MMS: LevelShutdown\n"); #endif if (g_bIsVspBridged && !were_plugins_loaded) @@ -596,7 +596,7 @@ bool loadGame, bool background) { #if SOURCE_ENGINE == SE_DOTA - Msg("MMS: LevelInit\n"); + DevMsg("MMS: LevelInit\n"); #endif ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); From 9af2b18a7e8b4f1957ebc591881070557ed020b0 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sun, 16 Apr 2017 16:25:34 -0400 Subject: [PATCH 43/44] Restore the comma to the people. --- loader/loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/loader.cpp b/loader/loader.cpp index ff6fa0e..47cffe4 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -89,7 +89,7 @@ static const char *backend_names[] = "2.blade", "2.insurgency", "2.contagion", - "2.bms" + "2.bms", }; #if defined _WIN32 From 7079862139334a6c1b0f2f0894af1b4d1783519b Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 22 Apr 2017 21:25:27 -0400 Subject: [PATCH 44/44] Exclude hookgen on non-x86 instead of non-Windows Dota. --- core/AMBuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/AMBuilder b/core/AMBuilder index e0327af..83edb80 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -25,7 +25,7 @@ for sdk_name in MMS.sdks: ] # Source2 hack. TODO: check this more deterministically, "are we doing an x64 build?" - if sdk.name != 'dota' or builder.target.platform == 'windows': + if builder.target.arch == 'x86': binary.sources += ['sourcehook/sourcehook_hookmangen.cpp'] nodes = builder.Add(binary) MMS.binaries += [nodes]