mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-02-21 14:54:14 +01:00
Initial import of gameinfo loader.
This commit is contained in:
parent
ce7a3beab0
commit
ad6f271a71
@ -8,7 +8,9 @@
|
|||||||
BINARY = server_i486.so
|
BINARY = server_i486.so
|
||||||
|
|
||||||
OBJECTS = loader.cpp \
|
OBJECTS = loader.cpp \
|
||||||
serverplugin.cpp
|
utility.cpp \
|
||||||
|
serverplugin.cpp \
|
||||||
|
gamedll.cpp
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||||
|
436
loader/gamedll.cpp
Normal file
436
loader/gamedll.cpp
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "loader.h"
|
||||||
|
#include <sh_memfuncinfo.h>
|
||||||
|
#include <sh_memory.h>
|
||||||
|
#include "utility.h"
|
||||||
|
#include "gamedll.h"
|
||||||
|
#include "valve_commandline.h"
|
||||||
|
|
||||||
|
class IServerGameDLL;
|
||||||
|
typedef ICommandLine *(*GetCommandLine)();
|
||||||
|
|
||||||
|
#define MAX_GAMEDLL_PATHS 10
|
||||||
|
|
||||||
|
IGameDllBridge* gamedll_bridge = NULL;
|
||||||
|
static int game_info_detected = 0;
|
||||||
|
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 IServerGameDLL *gamedll_iface = NULL;
|
||||||
|
static QueryValveInterface gamedll_qvi = NULL;
|
||||||
|
static int gamedll_version = 0;
|
||||||
|
|
||||||
|
#if defined _WIN32
|
||||||
|
#define TIER0_NAME "bin\\tier0.dll"
|
||||||
|
#define VSTDLIB_NAME "bin\\vstdlib.dll"
|
||||||
|
#define SERVER_NAME "server.dll"
|
||||||
|
#elif defined __linux__
|
||||||
|
#define TIER0_NAME "bin/tier0_i486.so"
|
||||||
|
#define VSTDLIB_NAME "bin/vstdlib_i486.so"
|
||||||
|
#define SERVER_NAME "server_i486.so"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mm_DetectGameInformation()
|
||||||
|
{
|
||||||
|
void *lib;
|
||||||
|
char error[255];
|
||||||
|
GetCommandLine valve_cmdline;
|
||||||
|
char mm_path[PLATFORM_MAX_PATH];
|
||||||
|
char lib_path[PLATFORM_MAX_PATH];
|
||||||
|
char game_name[PLATFORM_MAX_PATH];
|
||||||
|
char game_path[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
|
if (game_info_detected)
|
||||||
|
return game_info_detected == 1 ? true : false;
|
||||||
|
|
||||||
|
game_info_detected = -1;
|
||||||
|
|
||||||
|
if (!mm_ResolvePath(TIER0_NAME, lib_path, sizeof(lib_path)))
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not find path for: " TIER0_NAME);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lib = mm_LoadLibrary(lib_path, error, sizeof(error))) == NULL)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not load %s: %s", lib_path, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
valve_cmdline = (GetCommandLine)mm_GetLibAddress(lib, "CommandLine_Tier0");
|
||||||
|
if (valve_cmdline == NULL)
|
||||||
|
{
|
||||||
|
/* We probably have a Ship engine. */
|
||||||
|
mm_UnloadLibrary(lib);
|
||||||
|
if (!mm_ResolvePath(VSTDLIB_NAME, lib_path, sizeof(lib_path)))
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not find path for: " VSTDLIB_NAME);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lib = mm_LoadLibrary(lib_path, error, sizeof(error))) == NULL)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not load %s: %s", lib_path, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
valve_cmdline = (GetCommandLine)mm_GetLibAddress(lib, "CommandLine");
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_UnloadLibrary(lib);
|
||||||
|
|
||||||
|
if (valve_cmdline == NULL)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not locate any command line functionality");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mm_GetFileOfAddress((void*)mm_DetectGameInformation, mm_path, sizeof(mm_path)))
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not locate metamod loader library path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_Format(game_name,
|
||||||
|
sizeof(game_name),
|
||||||
|
"%s",
|
||||||
|
valve_cmdline()->ParmValue("-game", "hl2"));
|
||||||
|
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.txt", 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/" SERVER_NAME, lptr);
|
||||||
|
else
|
||||||
|
mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s/bin/" 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;
|
||||||
|
|
||||||
|
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 *isgd_orig_call = NULL;
|
||||||
|
|
||||||
|
class VEmptyClass
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class IServerGameDLL
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool DLLInit(QueryValveInterface engineFactory,
|
||||||
|
QueryValveInterface physicsFactory,
|
||||||
|
QueryValveInterface fileSystemFactory,
|
||||||
|
void *pGlobals)
|
||||||
|
{
|
||||||
|
MetamodBackend backend = mm_DetermineBackend(engineFactory);
|
||||||
|
|
||||||
|
char error[255];
|
||||||
|
if (backend == MMBackend_UNKNOWN)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Could not detect engine version");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mm_LoadMetamodLibrary(backend, error, sizeof(error)))
|
||||||
|
{
|
||||||
|
mm_LogFatal("Detected engine %d but could not load: %s", 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", backend);
|
||||||
|
}
|
||||||
|
gamedll_bridge = get_bridge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
strcpy(error, "Unknown error");
|
||||||
|
if (!gamedll_bridge->DLLInit_Pre(&info, error, sizeof(error)))
|
||||||
|
{
|
||||||
|
gamedll_bridge = NULL;
|
||||||
|
mm_UnloadMetamodLibrary();
|
||||||
|
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the original */
|
||||||
|
bool result;
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool (VEmptyClass::*mfpnew)(QueryValveInterface engineFactory,
|
||||||
|
QueryValveInterface physicsFactory,
|
||||||
|
QueryValveInterface fileSystemFactory,
|
||||||
|
void *pGlobals);
|
||||||
|
#if defined _WIN32
|
||||||
|
void *addr;
|
||||||
|
} u;
|
||||||
|
u.addr = isgd_orig_call;
|
||||||
|
#else
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
void *addr;
|
||||||
|
intptr_t adjustor;
|
||||||
|
} s;
|
||||||
|
} u;
|
||||||
|
u.s.addr = isgd_orig_call;
|
||||||
|
u.s.adjustor = 0;
|
||||||
|
#endif
|
||||||
|
result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory,
|
||||||
|
physicsFactory,
|
||||||
|
fileSystemFactory,
|
||||||
|
pGlobals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* :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();
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_PatchDllInit(false);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static IServerGameDLL isgd_thunk;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mm_PatchDllInit(bool patch)
|
||||||
|
{
|
||||||
|
void **vtable_src;
|
||||||
|
void **vtable_dest;
|
||||||
|
SourceHook::MemFuncInfo mfp;
|
||||||
|
|
||||||
|
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfp);
|
||||||
|
|
||||||
|
assert(mfp.isVirtual);
|
||||||
|
assert(mfp.thisptroffs == 0);
|
||||||
|
assert(mfp.vtbloffs == 0);
|
||||||
|
|
||||||
|
vtable_src = (void **)*(void **)&isgd_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(isgd_orig_call == NULL);
|
||||||
|
isgd_orig_call = vtable_dest[mfp.vtblindex];
|
||||||
|
vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(isgd_orig_call != NULL);
|
||||||
|
vtable_dest[mfp.vtblindex] = isgd_orig_call;
|
||||||
|
isgd_orig_call = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mm_PrepForGameLoad()
|
||||||
|
{
|
||||||
|
mm_PatchDllInit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
mm_GameDllRequest(const char *name, int *ret)
|
||||||
|
{
|
||||||
|
if (gamedll_lib != NULL && gamedll_bridge == NULL)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Requested unknown interface before game load: %s", name);
|
||||||
|
return gamedll_qvi(name, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(name, "ServerGameDLL", 13) == 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;
|
||||||
|
gamedll_iface = (IServerGameDLL *)ptr;
|
||||||
|
gamedll_qvi = qvi;
|
||||||
|
gamedll_version = atoi(&name[13]);
|
||||||
|
mm_PrepForGameLoad();
|
||||||
|
|
||||||
|
if (ret != NULL)
|
||||||
|
*ret = 0;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (game_info_detected == 0)
|
||||||
|
{
|
||||||
|
mm_LogFatal("Received interface request too early: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != NULL)
|
||||||
|
*ret = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
12
loader/gamedll.h
Normal file
12
loader/gamedll.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#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,10 +1,13 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "serverplugin.h"
|
#include "serverplugin.h"
|
||||||
|
#include "gamedll.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
static HMODULE mm_library = NULL;
|
static HMODULE mm_library = NULL;
|
||||||
static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log";
|
static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log";
|
||||||
@ -34,56 +37,6 @@ mm_LogFatal(const char *message, ...)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
#else
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *backend_names[3] =
|
static const char *backend_names[3] =
|
||||||
{
|
{
|
||||||
"1.ep1",
|
"1.ep1",
|
||||||
@ -100,7 +53,7 @@ static const char *backend_names[3] =
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
static void
|
void
|
||||||
mm_GetPlatformError(char *buffer, size_t maxlength)
|
mm_GetPlatformError(char *buffer, size_t maxlength)
|
||||||
{
|
{
|
||||||
DWORD dw = GetLastError();
|
DWORD dw = GetLastError();
|
||||||
@ -143,35 +96,16 @@ mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength)
|
|||||||
"metamod.%s" LIBRARY_MINEXT,
|
"metamod.%s" LIBRARY_MINEXT,
|
||||||
backend_names[backend]);
|
backend_names[backend]);
|
||||||
|
|
||||||
#if defined _WIN32
|
mm_library = mm_LoadLibrary(mm_path, buffer, maxlength);
|
||||||
mm_library = LoadLibrary(mm_path);
|
|
||||||
|
|
||||||
if (mm_library == NULL)
|
return (mm_library != NULL);
|
||||||
{
|
|
||||||
mm_GetPlatformError(buffer, maxlength);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#elif defined __linux__
|
|
||||||
mm_library = dlopen(mm_path, RTLD_NOW);
|
|
||||||
|
|
||||||
if (mm_library == NULL)
|
|
||||||
{
|
|
||||||
mm_Format(buffer, maxlength, "%s", dlerror());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mm_UnloadMetamodLibrary()
|
mm_UnloadMetamodLibrary()
|
||||||
{
|
{
|
||||||
#if defined _WIN32
|
mm_UnloadLibrary(mm_library);
|
||||||
FreeLibrary(mm_library);
|
mm_library = NULL;
|
||||||
#else
|
|
||||||
dlclose(mm_library);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
@ -187,35 +121,63 @@ mm_UnloadMetamodLibrary()
|
|||||||
EXPORT void *
|
EXPORT void *
|
||||||
CreateInterface(const char *name, int *ret)
|
CreateInterface(const char *name, int *ret)
|
||||||
{
|
{
|
||||||
if (mm_library != NULL)
|
/* If we've got a VSP bridge, do nothing. */
|
||||||
|
if (vsp_bridge != NULL)
|
||||||
{
|
{
|
||||||
if (ret != NULL)
|
if (ret != NULL)
|
||||||
*ret = 1;
|
*ret = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we've got a gamedll bridge, forward the request. */
|
||||||
|
if (gamedll_bridge != NULL)
|
||||||
|
return gamedll_bridge->QueryInterface(name, ret);
|
||||||
|
|
||||||
|
/* Otherwise, we're probably trying to load Metamod. */
|
||||||
void *ptr;
|
void *ptr;
|
||||||
if (strncmp(name, "ISERVERPLUGINCALLBACKS", 22) == 0)
|
if (strncmp(name, "ISERVERPLUGINCALLBACKS", 22) == 0)
|
||||||
{
|
|
||||||
ptr = mm_GetVspCallbacks(atoi(&name[22]));
|
ptr = mm_GetVspCallbacks(atoi(&name[22]));
|
||||||
if (ret != NULL)
|
else
|
||||||
*ret = ptr != NULL ? 0 : 1;
|
ptr = mm_GameDllRequest(name, ret);
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != NULL)
|
if (ret != NULL)
|
||||||
*ret = 1;
|
*ret = (ptr != NULL) ? 0 : 1;
|
||||||
|
|
||||||
return NULL;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *
|
void *
|
||||||
mm_GetProcAddress(const char *name)
|
mm_GetProcAddress(const char *name)
|
||||||
{
|
{
|
||||||
#if defined _WIN32
|
return mm_GetLibAddress(mm_library, name);
|
||||||
return GetProcAddress(mm_library, name);
|
}
|
||||||
#elif defined __linux__
|
|
||||||
return dlsym(mm_library, name);
|
MetamodBackend
|
||||||
#endif
|
mm_DetermineBackend(QueryValveInterface engineFactory)
|
||||||
|
{
|
||||||
|
/* Check for L4D */
|
||||||
|
if (engineFactory("VEngineServer022", NULL) != NULL &&
|
||||||
|
engineFactory("VEngineCvar007", NULL) != NULL)
|
||||||
|
{
|
||||||
|
return MMBackend_Left4Dead;
|
||||||
|
}
|
||||||
|
else if (engineFactory("VEngineServer021", NULL) != NULL)
|
||||||
|
{
|
||||||
|
/* Check for OB */
|
||||||
|
if (engineFactory("VEngineCvar004", NULL) != NULL &&
|
||||||
|
engineFactory("VModelInfoServer002", NULL) != NULL)
|
||||||
|
{
|
||||||
|
return MMBackend_Episode2;
|
||||||
|
}
|
||||||
|
/* Check for EP1 */
|
||||||
|
else if (engineFactory("VModelInfoServer001", NULL) != NULL &&
|
||||||
|
(engineFactory("VEngineCvar003", NULL) != NULL ||
|
||||||
|
engineFactory("VEngineCvar002", NULL) != NULL))
|
||||||
|
{
|
||||||
|
return MMBackend_Episode1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MMBackend_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,17 +9,26 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define PLATFORM_MAX_PATH MAX_PATH
|
#define PLATFORM_MAX_PATH MAX_PATH
|
||||||
#define SH_COMP SH_COMP_MSVC
|
#define SH_COMP SH_COMP_MSVC
|
||||||
|
#define PATH_SEP_STR "\\"
|
||||||
|
#define PATH_SEP_CHAR '\\'
|
||||||
|
#define ALT_SEP_CHAR '/'
|
||||||
#elif defined __linux__
|
#elif defined __linux__
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
typedef void * HMODULE;
|
typedef void * HMODULE;
|
||||||
#define PLATFORM_MAX_PATH PATH_MAX
|
#define PLATFORM_MAX_PATH PATH_MAX
|
||||||
#define SH_COMP SH_COMP_GCC
|
#define SH_COMP SH_COMP_GCC
|
||||||
|
#define PATH_SEP_STR "/"
|
||||||
|
#define PATH_SEP_CHAR '/'
|
||||||
|
#define ALT_SEP_CHAR '\\'
|
||||||
#else
|
#else
|
||||||
#error "OS detection failed"
|
#error "OS detection failed"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "loader_bridge.h"
|
||||||
|
|
||||||
#define SH_PTRSIZE sizeof(void*)
|
#define SH_PTRSIZE sizeof(void*)
|
||||||
|
|
||||||
enum MetamodBackend
|
enum MetamodBackend
|
||||||
@ -42,5 +51,8 @@ mm_UnloadMetamodLibrary();
|
|||||||
extern void
|
extern void
|
||||||
mm_LogFatal(const char *message, ...);
|
mm_LogFatal(const char *message, ...);
|
||||||
|
|
||||||
|
extern MetamodBackend
|
||||||
|
mm_DetermineBackend(QueryValveInterface qvi);
|
||||||
|
|
||||||
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_H_ */
|
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_H_ */
|
||||||
|
|
||||||
|
@ -20,5 +20,25 @@ public:
|
|||||||
virtual const char *GetDescription() = 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IGameDllBridge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength) = 0;
|
||||||
|
virtual void DLLInit_Post() = 0;
|
||||||
|
virtual void *QueryInterface(const char *name, int *ret) = 0;
|
||||||
|
virtual void Unload() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ */
|
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ */
|
||||||
|
|
||||||
|
@ -42,13 +42,14 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IVspBridge *vsp_bridge = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The vtable must match the general layout for ISPC. We modify the vtable
|
* The vtable must match the general layout for ISPC. We modify the vtable
|
||||||
* based on what we get back.
|
* based on what we get back.
|
||||||
*/
|
*/
|
||||||
class ServerPlugin
|
class ServerPlugin
|
||||||
{
|
{
|
||||||
IVspBridge* bridge;
|
|
||||||
unsigned int vsp_version;
|
unsigned int vsp_version;
|
||||||
bool load_allowed;
|
bool load_allowed;
|
||||||
public:
|
public:
|
||||||
@ -58,39 +59,16 @@ public:
|
|||||||
}
|
}
|
||||||
virtual bool Load(QueryValveInterface engineFactory, QueryValveInterface gsFactory)
|
virtual bool Load(QueryValveInterface engineFactory, QueryValveInterface gsFactory)
|
||||||
{
|
{
|
||||||
MetamodBackend backend = MMBackend_UNKNOWN;
|
|
||||||
|
|
||||||
if (!load_allowed)
|
if (!load_allowed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
load_allowed = false;
|
load_allowed = false;
|
||||||
|
|
||||||
/* Check for L4D */
|
MetamodBackend backend = mm_DetermineBackend(engineFactory);
|
||||||
if (engineFactory("VEngineServer022", NULL) != NULL &&
|
|
||||||
engineFactory("VEngineCvar007", NULL) != NULL)
|
|
||||||
{
|
|
||||||
backend = MMBackend_Left4Dead;
|
|
||||||
}
|
|
||||||
else if (engineFactory("VEngineServer021", NULL) != NULL)
|
|
||||||
{
|
|
||||||
/* Check for OB */
|
|
||||||
if (engineFactory("VEngineCvar004", NULL) != NULL &&
|
|
||||||
engineFactory("VModelInfoServer002", NULL) != NULL)
|
|
||||||
{
|
|
||||||
backend = MMBackend_Episode2;
|
|
||||||
}
|
|
||||||
/* Check for EP1 */
|
|
||||||
else if (engineFactory("VModelInfoServer001", NULL) != NULL &&
|
|
||||||
(engineFactory("VEngineCvar003", NULL) != NULL ||
|
|
||||||
engineFactory("VEngineCvar002", NULL) != NULL))
|
|
||||||
{
|
|
||||||
backend = MMBackend_Episode1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backend == MMBackend_UNKNOWN)
|
if (backend == MMBackend_UNKNOWN)
|
||||||
{
|
{
|
||||||
mm_LogFatal("Could not detect engine version, spewing stats:");
|
mm_LogFatal("Could not detect engine version");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (backend >= MMBackend_Episode2)
|
else if (backend >= MMBackend_Episode2)
|
||||||
@ -134,11 +112,11 @@ public:
|
|||||||
if (get_bridge == NULL)
|
if (get_bridge == NULL)
|
||||||
{
|
{
|
||||||
mm_UnloadMetamodLibrary();
|
mm_UnloadMetamodLibrary();
|
||||||
mm_LogFatal("Detected engine %d but could not find GetVspBridge callback.", backend);
|
mm_LogFatal("Detected engine %d but could not find GetVspBridge callback", backend);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge = get_bridge();
|
vsp_bridge = get_bridge();
|
||||||
|
|
||||||
vsp_bridge_info info;
|
vsp_bridge_info info;
|
||||||
|
|
||||||
@ -148,8 +126,9 @@ public:
|
|||||||
info.vsp_version = vsp_version;
|
info.vsp_version = vsp_version;
|
||||||
|
|
||||||
strcpy(error, "Unknown error");
|
strcpy(error, "Unknown error");
|
||||||
if (!bridge->Load(&info, error, sizeof(error)))
|
if (!vsp_bridge->Load(&info, error, sizeof(error)))
|
||||||
{
|
{
|
||||||
|
vsp_bridge = NULL;
|
||||||
mm_UnloadMetamodLibrary();
|
mm_UnloadMetamodLibrary();
|
||||||
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
|
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
|
||||||
return false;
|
return false;
|
||||||
@ -159,9 +138,9 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void Unload()
|
virtual void Unload()
|
||||||
{
|
{
|
||||||
if (bridge == NULL)
|
if (vsp_bridge == NULL)
|
||||||
return;
|
return;
|
||||||
bridge->Unload();
|
vsp_bridge->Unload();
|
||||||
mm_UnloadMetamodLibrary();
|
mm_UnloadMetamodLibrary();
|
||||||
}
|
}
|
||||||
virtual void Pause()
|
virtual void Pause()
|
||||||
@ -172,9 +151,9 @@ public:
|
|||||||
}
|
}
|
||||||
virtual const char *GetPluginDescription()
|
virtual const char *GetPluginDescription()
|
||||||
{
|
{
|
||||||
if (bridge == NULL)
|
if (vsp_bridge == NULL)
|
||||||
return "Metamod:Source Loader Shim";
|
return "Metamod:Source Loader Shim";
|
||||||
return bridge->GetDescription();
|
return vsp_bridge->GetDescription();
|
||||||
}
|
}
|
||||||
virtual void LevelInit(char const *pMapName)
|
virtual void LevelInit(char const *pMapName)
|
||||||
{
|
{
|
||||||
@ -232,17 +211,13 @@ public:
|
|||||||
vsp_version = version;
|
vsp_version = version;
|
||||||
load_allowed = true;
|
load_allowed = true;
|
||||||
}
|
}
|
||||||
bool IsLoaded()
|
|
||||||
{
|
|
||||||
return bridge != NULL;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerPlugin mm_vsp_callbacks;
|
ServerPlugin mm_vsp_callbacks;
|
||||||
|
|
||||||
void *mm_GetVspCallbacks(unsigned int version)
|
void *mm_GetVspCallbacks(unsigned int version)
|
||||||
{
|
{
|
||||||
if (mm_vsp_callbacks.IsLoaded())
|
if (vsp_bridge != NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Only support versions 1 or 2 right now */
|
/* Only support versions 1 or 2 right now */
|
||||||
|
@ -6,5 +6,7 @@
|
|||||||
extern void *
|
extern void *
|
||||||
mm_GetVspCallbacks(unsigned int version);
|
mm_GetVspCallbacks(unsigned int version);
|
||||||
|
|
||||||
|
extern IVspBridge *vsp_bridge;
|
||||||
|
|
||||||
#endif /* _INCLUDE_METAMOD_SOURCE_SERVERPLUGINS_H_ */
|
#endif /* _INCLUDE_METAMOD_SOURCE_SERVERPLUGINS_H_ */
|
||||||
|
|
||||||
|
303
loader/utility.cpp
Normal file
303
loader/utility.cpp
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "loader.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
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 >= 0; 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)
|
||||||
|
{
|
||||||
|
#if defined _WIN32
|
||||||
|
return _fullpath(buffer, path, maxlength) != NULL;
|
||||||
|
#elif defined __linux__
|
||||||
|
assert(maxlength >= PATH_MAX);
|
||||||
|
return realpath(path, buffer) != NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
mm_LoadLibrary(const char *path, char *buffer, size_t maxlength)
|
||||||
|
{
|
||||||
|
void *lib;
|
||||||
|
|
||||||
|
#if defined _WIN32
|
||||||
|
lib = LoadLibrary(path);
|
||||||
|
|
||||||
|
if (lib == NULL)
|
||||||
|
{
|
||||||
|
mm_GetPlatformError(buffer, maxlength);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#elif defined __linux__
|
||||||
|
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(lib, name);
|
||||||
|
#elif defined __linux__
|
||||||
|
return dlsym(lib, name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_UnloadLibrary(void *lib)
|
||||||
|
{
|
||||||
|
#if defined _WIN32
|
||||||
|
FreeLibrary(lib);
|
||||||
|
#else
|
||||||
|
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__
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
43
loader/utility.h
Normal file
43
loader/utility.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#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_ */
|
||||||
|
|
28
loader/valve_commandline.h
Normal file
28
loader/valve_commandline.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef _INCLUDE_VALVE_COMMAND_LINE_H_
|
||||||
|
#define _INCLUDE_VALVE_COMMAND_LINE_H_
|
||||||
|
|
||||||
|
class ICommandLine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void CreateCmdLine( const char *commandline ) = 0;
|
||||||
|
virtual void CreateCmdLine( int argc, char **argv ) = 0;
|
||||||
|
virtual const char *GetCmdLine( void ) const = 0;
|
||||||
|
|
||||||
|
// Check whether a particular parameter exists
|
||||||
|
virtual const char *CheckParm( const char *psz, const char **ppszValue = 0 ) const = 0;
|
||||||
|
virtual void RemoveParm( const char *parm ) = 0;
|
||||||
|
virtual void AppendParm( const char *pszParm, const char *pszValues ) = 0;
|
||||||
|
|
||||||
|
// Returns the argument after the one specified, or the default if not found
|
||||||
|
virtual const char *ParmValue( const char *psz, const char *pDefaultVal = 0 ) const = 0;
|
||||||
|
virtual int ParmValue( const char *psz, int nDefaultVal ) const = 0;
|
||||||
|
virtual float ParmValue( const char *psz, float flDefaultVal ) const = 0;
|
||||||
|
|
||||||
|
// Gets at particular parameters
|
||||||
|
virtual int ParmCount() const = 0;
|
||||||
|
virtual int FindParm( const char *psz ) const = 0; // Returns 0 if not found.
|
||||||
|
virtual const char* GetParm( int nIndex ) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE_VALVE_COMMAND_LINE_H_ */
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user