mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-02-21 14:54:14 +01:00
Merge loader, loader2. Rename env var HL2SDKS2 -> HL2SDKSOURCE2.
This commit is contained in:
parent
4b75bcb431
commit
30b7be46a8
@ -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',
|
||||
]
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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__
|
||||
|
@ -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, ...);
|
||||
|
@ -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"'])
|
@ -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 <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include "loader2.h"
|
||||
#include <sh_memfuncinfo.h>
|
||||
#include <sh_memory.h>
|
||||
#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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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 <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "loader2.h"
|
||||
#include "gamedll.h"
|
||||
#include "utility.h"
|
||||
#if defined __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
@ -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 <windows.h>
|
||||
#include <direct.h>
|
||||
#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 <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#if SH_SYS == SH_SYS_APPLE
|
||||
#include <sys/syslimits.h>
|
||||
#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 <loader_public.h>
|
||||
#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_ */
|
||||
|
@ -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 <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include "loader2.h"
|
||||
#include "utility.h"
|
||||
|
||||
#if defined __linux__
|
||||
#include <link.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
#elif defined __APPLE__
|
||||
#include <mach-o/loader.h>
|
||||
#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<uintptr_t>(info.AllocationBase);
|
||||
|
||||
/* All this is for our insane sanity checks :o */
|
||||
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
||||
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(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<uintptr_t>(info.dli_fbase);
|
||||
file = reinterpret_cast<Elf32_Ehdr *>(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<Elf32_Phdr *>(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<void *>(baseAddr);
|
||||
|
||||
return true;
|
||||
}
|
@ -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 <stddef.h>
|
||||
|
||||
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_ */
|
||||
|
@ -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_
|
Loading…
x
Reference in New Issue
Block a user