1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-29 11:24:19 +01:00

Added gamedll bridging to ep2/l4d provider (bug 3412).

This commit is contained in:
David Anderson 2008-11-23 23:22:33 -06:00
parent 18251be939
commit 105665bdaf
10 changed files with 77 additions and 443 deletions

View File

@ -19,7 +19,8 @@ OBJECTS = metamod.cpp \
provider/console.cpp \ provider/console.cpp \
provider/provider_ep2.cpp \ provider/provider_ep2.cpp \
provider/vsp_listener.cpp \ provider/vsp_listener.cpp \
vsp_bridge.cpp vsp_bridge.cpp \
gamedll_bridge.cpp
############################################## ##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###

64
core/gamedll_bridge.cpp Normal file
View File

@ -0,0 +1,64 @@
#include <assert.h>
#include "metamod.h"
#include "metamod_plugins.h"
#include "metamod_util.h"
#include <loader_bridge.h>
#include "provider/provider_ep2.h"
using namespace SourceMM;
class GameDllBridge : public IGameDllBridge
{
public:
virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength)
{
if (!mm_DetectGameInformation())
{
UTIL_Format(buffer, maxlength, "Metamod:Source failed to detect game paths; cannot load.");
return false;
}
server = (IServerGameDLL *)info->isgd;
g_Metamod.SetGameDLLInfo((CreateInterfaceFn)info->gsFactory,
info->dllVersion,
true);
mm_InitializeGlobals((CreateInterfaceFn)info->engineFactory,
(CreateInterfaceFn)info->physicsFactory,
(CreateInterfaceFn)info->fsFactory,
(CGlobalVars*)info->pGlobals);
mm_InitializeForLoad();
mm_StartupMetamod(false);
return true;
}
virtual void DLLInit_Post(int *isgdUnload)
{
SourceHook::MemFuncInfo mfi;
mfi.isVirtual = false;
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
assert(mfi.isVirtual);
assert(mfi.vtbloffs == 0);
assert(mfi.thisptroffs == 0);
*isgdUnload = mfi.vtblindex;
g_PluginMngr.SetAllLoaded();
}
virtual void *QueryInterface(const char *iface, int *ret)
{
return g_Metamod.GetServerFactory(true)(iface, ret);
}
virtual void Unload()
{
mm_UnloadMetamod();
}
};
GameDllBridge mm16_gamedll_bridge;
SMM_API IGameDllBridge *
GetGameDllBridge()
{
return &mm16_gamedll_bridge;
}

View File

@ -45,26 +45,9 @@ using namespace SourceHook::Impl;
* @file sourcemm.cpp * @file sourcemm.cpp
*/ */
SH_DECL_MANUALHOOK4(SGD_DLLInit, 0, 0, 0, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool);
SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0); SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0);
SH_DECL_MANUALHOOK0_void(SGD_DLLShutdown, 0, 0, 0);
static bool
Handler_DLLInit(CreateInterfaceFn engineFactory,
CreateInterfaceFn physicsFactory,
CreateInterfaceFn filesystemFactory,
CGlobalVars *pGlobals);
static bool
Handler_DLLInit_Post(CreateInterfaceFn engineFactory,
CreateInterfaceFn physicsFactory,
CreateInterfaceFn filesystemFactory,
CGlobalVars *pGlobals);
static void
Handler_DLLShutdown();
static void static void
Handler_LevelShutdown(); Handler_LevelShutdown();
@ -88,14 +71,12 @@ LookForVDFs(const char *dir);
struct game_dll_t struct game_dll_t
{ {
HINSTANCE lib;
CreateInterfaceFn factory; CreateInterfaceFn factory;
}; };
static String mod_path; static String mod_path;
static String metamod_path; static String metamod_path;
static String full_bin_path; static String full_bin_path;
static bool parsed_game_info = false;
static int vsp_version = 0; static int vsp_version = 0;
static int gamedll_version = 0; static int gamedll_version = 0;
static int engine_build = SOURCE_ENGINE_UNKNOWN; static int engine_build = SOURCE_ENGINE_UNKNOWN;
@ -125,9 +106,6 @@ CSourceHookImpl g_SourceHook;
ISourceHook *g_SHPtr = &g_SourceHook; ISourceHook *g_SHPtr = &g_SourceHook;
SourceMM::ISmmAPI *g_pMetamod = &g_Metamod; SourceMM::ISmmAPI *g_pMetamod = &g_Metamod;
static void
ClearGamedllList();
/* Helper Macro */ /* Helper Macro */
#define IFACE_MACRO(orig,nam) \ #define IFACE_MACRO(orig,nam) \
CPluginManager::CPlugin *pl; \ CPluginManager::CPlugin *pl; \
@ -182,14 +160,6 @@ mm_InitializeForLoad()
SourceHook::MemFuncInfo info; SourceHook::MemFuncInfo info;
if (!provider->GetHookInfo(ProvidedHook_DLLInit, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLInit");
}
SH_MANUALHOOK_RECONFIGURE(SGD_DLLInit, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit, false);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLInit, server, Handler_DLLInit_Post, true);
if (!provider->GetHookInfo(ProvidedHook_GameInit, &info)) if (!provider->GetHookInfo(ProvidedHook_GameInit, &info))
{ {
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::GameInit"); provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::GameInit");
@ -210,13 +180,6 @@ mm_InitializeForLoad()
} }
SH_MANUALHOOK_RECONFIGURE(SGD_LevelShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs); SH_MANUALHOOK_RECONFIGURE(SGD_LevelShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelShutdown, server, Handler_LevelShutdown, true); SH_ADD_MANUALHOOK_STATICFUNC(SGD_LevelShutdown, server, Handler_LevelShutdown, true);
if (!provider->GetHookInfo(ProvidedHook_DLLShutdown, &info))
{
provider->DisplayError("Metamod:Source could not find a valid hook for IServerGameDLL::DLLShutdown");
}
SH_MANUALHOOK_RECONFIGURE(SGD_DLLShutdown, info.vtblindex, info.vtbloffs, info.thisptroffs);
SH_ADD_MANUALHOOK_STATICFUNC(SGD_DLLShutdown, server, Handler_DLLShutdown, false);
} }
bool bool
@ -245,266 +208,12 @@ mm_DetectGameInformation()
return true; return true;
} }
/* This is where the magic happens */ void *
SMM_API void * ServerFactory(const char *iface, int *ret)
CreateInterface(const char *iface, int *ret)
{ {
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
if (strcmp(iface, METAMOD_PLAPI_NAME) == 0)
{
provider->DisplayWarning("Do not try loading Metamod:Source as a plugin.\n");
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
if (!g_bIsVspBridged && strncmp(iface, "ISERVERPLUGINCALLBACKS", 22) == 0)
{
if (vsp_callbacks != NULL && atoi(&iface[22]) != vsp_version)
{
if (ret != NULL)
*ret = IFACE_FAILED;
return NULL;
}
vsp_version = atoi(&iface[22]);
vsp_callbacks = provider->GetVSPCallbacks(vsp_version);
if (ret)
*ret = (vsp_callbacks != NULL) ? IFACE_OK : IFACE_FAILED;
if (vsp_callbacks == NULL)
vsp_version = 0;
return vsp_callbacks;
}
if (g_bIsVspBridged)
{
IFACE_MACRO(gamedll_info.factory, GameDLL);
}
if (!parsed_game_info)
{
parsed_game_info = true;
if (!mm_DetectGameInformation())
{
provider->DisplayError("GetFileOfAddress() failed! Metamod cannot load.\n");
return NULL;
}
char temp_path[PATH_SIZE];
/* Path to gameinfo.txt */
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s", mod_path.c_str(), "gameinfo.txt");
FILE *fp = fopen(temp_path, "rt");
if (!fp)
{
provider->DisplayError("Unable to open gameinfo.txt! Metamod cannot load.\n");
return NULL;
}
char buffer[255];
char key[128], val[128];
bool search = false;
bool gamebin = false;
char *ptr;
const char *lptr;
char cur_path[PATH_SIZE];
getcwd(cur_path, PATH_SIZE);
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
{
UTIL_TrimComments(buffer);
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
if (stricmp(buffer, "SearchPaths") == 0)
{
search = true;
}
if (!search)
{
continue;
}
UTIL_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
if (stricmp(key, "Game") == 0 || stricmp(key, "GameBin") == 0)
{
if (stricmp(key, "Game") == 0)
{
gamebin = false;
}
else
{
gamebin = true;
}
if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0)
{
ptr = &(val[sizeof("|gameinfo_path|") - 1]);
if (ptr[0] == '.')
{
ptr++;
}
lptr = mod_path.c_str();
} else {
ptr = val;
lptr = cur_path;
}
size_t ptr_len = strlen(ptr);
if (ptr[ptr_len] == '/' || ptr[ptr_len] == '\\')
{
ptr[--ptr_len] = '\0';
}
/* No need to append "bin" if key is GameBin */
if (gamebin)
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
}
else if (!ptr[0])
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
}
else
{
g_Metamod.PathFormat(temp_path, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
}
/* If not path to SourceMM... */
if (!UTIL_PathCmp(metamod_path.c_str(), temp_path))
{
FILE *temp_fp = fopen(temp_path, "rb");
if (!temp_fp)
{
continue;
}
fclose(temp_fp);
/* Search for a matching game dll */
List<game_dll_t *>::iterator iter;
game_dll_t *pCheck;
bool found = false;
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
{
pCheck = (*iter);
if (GetFileOfAddress((void *)pCheck->factory, buffer, sizeof(buffer)))
{
if (UTIL_PathCmp(temp_path, buffer))
{
found = true;
break;
}
}
}
if (found)
{
continue;
}
HINSTANCE gamedll = dlmount(temp_path);
if (gamedll == NULL)
{
continue;
}
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
if (fn == NULL)
{
dlclose(gamedll);
continue;
}
game_dll_t *pInfo = new game_dll_t;
pInfo->factory = fn;
pInfo->lib = gamedll;
gamedll_list.push_back(pInfo);
break;
}
}
}
fclose(fp);
}
if (!is_gamedll_loaded)
{
if (strncmp(iface, "ServerGameDLL", 13) == 0)
{
List<game_dll_t *>::iterator iter;
game_dll_t *pInfo;
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
{
pInfo = (*iter);
if ((server = (IServerGameDLL *)((pInfo->factory)(iface, ret))) != NULL)
{
if ((gamedll_version = provider->TryServerGameDLL(iface)) != 0)
{
/* We have a match. Erase us from the list and save our info. */
gamedll_list.erase(iter);
gamedll_info = *pInfo;
delete pInfo;
is_gamedll_loaded = true;
break;
}
/* :TODO: error otherwise? */
}
}
if (is_gamedll_loaded)
{
ClearGamedllList();
mm_InitializeForLoad();
}
else
{
if (ret)
{
*ret = IFACE_FAILED;
}
return NULL;
}
}
else
{
/* wtf do we do... */
/* :TODO: .. something a bit more intelligent? */
provider->DisplayError("Engine requested unknown interface before GameDLL was known!\n");
return NULL;
}
}
/* If we got here, there's definitely a GameDLL */
IFACE_MACRO(gamedll_info.factory, GameDLL); IFACE_MACRO(gamedll_info.factory, GameDLL);
} }
static void
ClearGamedllList()
{
List<game_dll_t *>::iterator iter;
game_dll_t *pInfo;
for (iter = gamedll_list.begin(); iter != gamedll_list.end(); iter++)
{
pInfo = (*iter);
dlclose(pInfo->lib);
delete pInfo;
}
gamedll_list.clear();
}
int int
mm_LoadPluginsFromFile(const char *_file) mm_LoadPluginsFromFile(const char *_file)
{ {
@ -813,18 +522,6 @@ mm_InitializeGlobals(CreateInterfaceFn engineFactory,
provider->Notify_DLLInit_Pre(engineFactory, gamedll_info.factory); provider->Notify_DLLInit_Pre(engineFactory, gamedll_info.factory);
} }
static bool
Handler_DLLInit(CreateInterfaceFn engineFactory,
CreateInterfaceFn physicsFactory,
CreateInterfaceFn filesystemFactory,
CGlobalVars *pGlobals)
{
mm_InitializeGlobals(engineFactory, physicsFactory, filesystemFactory, pGlobals);
mm_StartupMetamod(false);
RETURN_META_VALUE(MRES_IGNORED, true);
}
static bool static bool
Handler_GameInit() Handler_GameInit()
{ {
@ -846,16 +543,6 @@ Handler_GameInit()
RETURN_META_VALUE(MRES_IGNORED, true); RETURN_META_VALUE(MRES_IGNORED, true);
} }
static bool
Handler_DLLInit_Post(CreateInterfaceFn engineFactory,
CreateInterfaceFn physicsFactory,
CreateInterfaceFn filesystemFactory,
CGlobalVars *pGlobals)
{
g_PluginMngr.SetAllLoaded();
RETURN_META_VALUE(MRES_IGNORED, true);
}
void void
mm_UnloadMetamod() mm_UnloadMetamod()
{ {
@ -864,25 +551,7 @@ mm_UnloadMetamod()
provider->Notify_DLLShutdown_Pre(); provider->Notify_DLLShutdown_Pre();
if (is_gamedll_loaded)
{
SH_CALL(server, &IServerGameDLL::DLLShutdown)();
}
g_SourceHook.CompleteShutdown(); g_SourceHook.CompleteShutdown();
if (is_gamedll_loaded && gamedll_info.lib)
{
dlclose(gamedll_info.lib);
is_gamedll_loaded = false;
}
}
static void
Handler_DLLShutdown()
{
mm_UnloadMetamod();
RETURN_META(MRES_SUPERCEDE);
} }
static void static void
@ -973,7 +642,7 @@ CreateInterfaceFn MetamodSource::GetFileSystemFactory(bool syn/* =true */)
CreateInterfaceFn MetamodSource::GetServerFactory(bool syn/* =true */) CreateInterfaceFn MetamodSource::GetServerFactory(bool syn/* =true */)
{ {
if (syn) if (syn)
return CreateInterface; return ServerFactory;
return gamedll_info.factory; return gamedll_info.factory;
} }
@ -1408,10 +1077,11 @@ bool MetamodSource::IsLoadedAsGameDLL()
return is_gamedll_loaded; return is_gamedll_loaded;
} }
void MetamodSource::SetGameDLLInfo(CreateInterfaceFn serverFactory, int version) void MetamodSource::SetGameDLLInfo(CreateInterfaceFn serverFactory, int version, bool loaded)
{ {
gamedll_info.factory = serverFactory; gamedll_info.factory = serverFactory;
gamedll_version = version; gamedll_version = version;
is_gamedll_loaded = loaded;
} }
static void static void

View File

@ -98,7 +98,7 @@ public:
const char *GetPluginsFile(); const char *GetPluginsFile();
void UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand); void UnregisterConCommandBase(PluginId id, ConCommandBase *pCommand);
void NotifyVSPListening(IServerPluginCallbacks *callbacks); void NotifyVSPListening(IServerPluginCallbacks *callbacks);
void SetGameDLLInfo(CreateInterfaceFn serverFactory, int version); void SetGameDLLInfo(CreateInterfaceFn serverFactory, int version, bool loaded);
}; };
bool bool

View File

@ -41,8 +41,6 @@ namespace SourceMM
{ {
ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */ ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */
ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */ ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */
ProvidedHook_DLLInit = 2, /**< IServerGameDLL::DLLInit */
ProvidedHook_DLLShutdown = 3, /**< IServerGameDLL::DLLShutdown */
ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */ ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */
}; };

View File

@ -99,91 +99,6 @@ void UTIL_TrimRight(char *buffer)
} }
} }
/* :TODO: this should skip string literals */
void UTIL_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 UTIL_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 UTIL_PathCmp(const char *path1, const char *path2) bool UTIL_PathCmp(const char *path1, const char *path2)
{ {
size_t pos1 = 0, pos2 = 0; size_t pos1 = 0, pos2 = 0;

View File

@ -45,11 +45,6 @@
*/ */
const char *UTIL_GetExtension(const char *file); const char *UTIL_GetExtension(const char *file);
/**
* @brief Removes C-style comments from string.
*/
void UTIL_TrimComments(char *buffer);
/** /**
* @brief Removes whitespace characters from left side of string. * @brief Removes whitespace characters from left side of string.
*/ */
@ -60,11 +55,6 @@ void UTIL_TrimLeft(char *buffer);
*/ */
void UTIL_TrimRight(char *buffer); void UTIL_TrimRight(char *buffer);
/**
* @brief Breaks a string at the first space until it reaches a non-space.
*/
void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2);
/** /**
* @brief Compares two file paths. * @brief Compares two file paths.
*/ */

View File

@ -414,6 +414,10 @@
RelativePath="..\vsp_bridge.cpp" RelativePath="..\vsp_bridge.cpp"
> >
</File> </File>
<File
RelativePath="..\gamedll_bridge.cpp"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Header Files" Name="Header Files"

View File

@ -258,14 +258,6 @@ bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInf
{ {
SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi); SourceHook::GetFuncInfo(&IServerGameDLL::GameInit, mfi);
} }
else if (hook == ProvidedHook_DLLShutdown)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfi);
}
else if (hook == ProvidedHook_DLLInit)
{
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfi);
}
*pInfo = mfi; *pInfo = mfi;

View File

@ -47,7 +47,7 @@ public:
gamedll_iface[15] = '0' + i; gamedll_iface[15] = '0' + i;
if ((server = (IServerGameDLL *)info->gsFactory(gamedll_iface, NULL)) != NULL) if ((server = (IServerGameDLL *)info->gsFactory(gamedll_iface, NULL)) != NULL)
{ {
g_Metamod.SetGameDLLInfo((CreateInterfaceFn)info->gsFactory, i); g_Metamod.SetGameDLLInfo((CreateInterfaceFn)info->gsFactory, i, false);
break; break;
} }
} }