mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-01-19 08:52:34 +01:00
Initial import of core-legacy as a gameinfo provider.
This commit is contained in:
parent
ad6f271a71
commit
110b1f3a10
@ -460,11 +460,12 @@ void CSmmAPI::LoadAsVSP()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *usepath = g_SmmPath.c_str();
|
char our_path[PATH_SIZE];
|
||||||
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_file, g_SmmPath.c_str()))
|
GetFileOfAddress((void*)LoadAsGameDLL, our_path, sizeof(our_path));
|
||||||
{
|
|
||||||
|
const char *usepath = our_path;
|
||||||
|
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_file, our_path))
|
||||||
usepath = rel_path;
|
usepath = rel_path;
|
||||||
}
|
|
||||||
|
|
||||||
char command[PATH_SIZE * 2];
|
char command[PATH_SIZE * 2];
|
||||||
g_VspListener.SetLoadable(true);
|
g_VspListener.SetLoadable(true);
|
||||||
@ -475,7 +476,7 @@ void CSmmAPI::LoadAsVSP()
|
|||||||
void CSmmAPI::EnableVSPListener()
|
void CSmmAPI::EnableVSPListener()
|
||||||
{
|
{
|
||||||
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
|
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
|
||||||
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded() && !g_bIsBridgedAsVsp)
|
if (g_bGameInit && !m_VSP && !g_VspListener.IsLoaded() && !g_bIsBridgedAsVsp)
|
||||||
{
|
{
|
||||||
LoadAsVSP();
|
LoadAsVSP();
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ OBJECTS = oslink.cpp \
|
|||||||
CPlugin.cpp \
|
CPlugin.cpp \
|
||||||
vsp_listener.cpp \
|
vsp_listener.cpp \
|
||||||
vsp_bridge.cpp \
|
vsp_bridge.cpp \
|
||||||
|
gamedll_bridge.cpp \
|
||||||
sourcehook/sourcehook.cpp
|
sourcehook/sourcehook.cpp
|
||||||
|
|
||||||
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
|
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||||
|
@ -157,10 +157,13 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (strcmp(command, "game") == 0) {
|
} else if (strcmp(command, "game") == 0) {
|
||||||
|
char bin_path[PATH_SIZE];
|
||||||
|
GetFileOfAddress((void*)g_GameDll.factory, bin_path, sizeof(bin_path));
|
||||||
|
|
||||||
CONMSG("GameDLL Information\n");
|
CONMSG("GameDLL Information\n");
|
||||||
CONMSG(" Description: %s\n", g_GameDll.pGameDLL->GetGameDescription());
|
CONMSG(" Description: %s\n", g_GameDll.pGameDLL->GetGameDescription());
|
||||||
CONMSG(" Mod Path: %s\n", g_ModPath.c_str());
|
CONMSG(" Mod Path: %s\n", g_ModPath.c_str());
|
||||||
CONMSG(" DLL Path: %s\n", g_BinPath.c_str());
|
CONMSG(" DLL Path: %s\n", bin_path);
|
||||||
CONMSG(" Interface: ServerGameDLL%03d\n", g_GameDllVersion);
|
CONMSG(" Interface: ServerGameDLL%03d\n", g_GameDllVersion);
|
||||||
|
|
||||||
// Display user messages
|
// Display user messages
|
||||||
|
91
core-legacy/gamedll_bridge.cpp
Normal file
91
core-legacy/gamedll_bridge.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "sourcemm.h"
|
||||||
|
#include "CPlugin.h"
|
||||||
|
#include <loader_bridge.h>
|
||||||
|
|
||||||
|
using namespace SourceMM;
|
||||||
|
|
||||||
|
#define IFACE_MACRO(orig,nam) \
|
||||||
|
CPluginManager::CPlugin *pl; \
|
||||||
|
SourceHook::List<CPluginEventHandler>::iterator event; \
|
||||||
|
IMetamodListener *api; \
|
||||||
|
int mret = 0; \
|
||||||
|
void *val = NULL; \
|
||||||
|
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||||
|
pl = (*iter); \
|
||||||
|
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||||
|
api = (*event).event; \
|
||||||
|
mret = IFACE_FAILED; \
|
||||||
|
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
|
||||||
|
if (ret) *ret = mret; \
|
||||||
|
return val; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return (orig)(iface, ret);
|
||||||
|
|
||||||
|
|
||||||
|
class GameDllBridge : public IGameDllBridge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength)
|
||||||
|
{
|
||||||
|
assert(!g_GameDll.loaded && !g_bIsBridgedAsVsp);
|
||||||
|
LoadAsGameDLL(info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual void DLLInit_Post()
|
||||||
|
{
|
||||||
|
g_PluginMngr.SetAllLoaded();
|
||||||
|
}
|
||||||
|
virtual void *QueryInterface(const char *iface, int *ret)
|
||||||
|
{
|
||||||
|
/* We use this interface for responding to the meta client command */
|
||||||
|
if (strncmp(iface, "ServerGameClients", 17) == 0)
|
||||||
|
{
|
||||||
|
void *ptr = (g_GameDll.factory)(iface, ret);
|
||||||
|
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got here, there's definitely a GameDLL */
|
||||||
|
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
||||||
|
}
|
||||||
|
virtual void Unload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GameDllBridge mm14_gamedll_bridge;
|
||||||
|
|
||||||
|
SMM_API IGameDllBridge *
|
||||||
|
GetGameDllBridge()
|
||||||
|
{
|
||||||
|
return &mm14_gamedll_bridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||||
|
* the engine's real engineFactory.
|
||||||
|
*/
|
||||||
|
void *EngineFactory(const char *iface, int *ret)
|
||||||
|
{
|
||||||
|
IFACE_MACRO(g_Engine.engineFactory, Engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||||
|
* the engine's real physicsFactory.
|
||||||
|
*/
|
||||||
|
void *PhysicsFactory(const char *iface, int *ret)
|
||||||
|
{
|
||||||
|
IFACE_MACRO(g_Engine.physicsFactory, Physics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||||
|
* the engine's real fileSystemFactory.
|
||||||
|
*/
|
||||||
|
void *FileSystemFactory(const char *iface, int *ret)
|
||||||
|
{
|
||||||
|
IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -32,66 +32,45 @@ using namespace SourceMM;
|
|||||||
#undef CommandLine
|
#undef CommandLine
|
||||||
DLL_IMPORT ICommandLine *CommandLine();
|
DLL_IMPORT ICommandLine *CommandLine();
|
||||||
|
|
||||||
SH_DECL_HOOK4(IServerGameDLL, DLLInit, SH_NOATTRIB, false, bool, CreateInterfaceFn, CreateInterfaceFn, CreateInterfaceFn, CGlobalVars *);
|
|
||||||
SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, SH_NOATTRIB, false);
|
SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, SH_NOATTRIB, false);
|
||||||
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
|
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
|
||||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
|
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
|
||||||
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||||
SH_DECL_HOOK0(IServerGameDLL, GameInit, SH_NOATTRIB, false, bool);
|
SH_DECL_HOOK0(IServerGameDLL, GameInit, SH_NOATTRIB, false, bool);
|
||||||
|
|
||||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
|
||||||
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals);
|
|
||||||
void DLLShutdown_handler();
|
void DLLShutdown_handler();
|
||||||
void LevelShutdown_handler();
|
void LevelShutdown_handler();
|
||||||
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
bool LevelInit_handler(char const *pMapName,
|
||||||
|
char const *pMapEntities,
|
||||||
|
char const *pOldLevel,
|
||||||
|
char const *pLandmarkName,
|
||||||
|
bool loadGame,
|
||||||
|
bool background);
|
||||||
bool GameInit_handler();
|
bool GameInit_handler();
|
||||||
void LookForVDFs(const char *dir);
|
void LookForVDFs(const char *dir);
|
||||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
bool KVLoadFromFile(KeyValues *kv,
|
||||||
|
IBaseFileSystem *filesystem,
|
||||||
|
const char *resourceName,
|
||||||
|
const char *pathID = NULL);
|
||||||
|
|
||||||
GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
|
GameDllInfo g_GameDll = {false, NULL, NULL, NULL};
|
||||||
EngineInfo g_Engine;
|
EngineInfo g_Engine;
|
||||||
SourceHook::CSourceHookImpl g_SourceHook;
|
SourceHook::CSourceHookImpl g_SourceHook;
|
||||||
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
|
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
|
||||||
SourceHook::String g_ModPath;
|
SourceHook::String g_ModPath;
|
||||||
SourceHook::String g_BinPath;
|
|
||||||
SourceHook::String g_SmmPath;
|
|
||||||
PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */
|
PluginId g_PLID = Pl_Console; /* Technically, SourceMM is the "Console" plugin... :p */
|
||||||
bool bInFirstLevel = true;
|
static bool bInFirstLevel = true;
|
||||||
bool gParsedGameInfo = false;
|
bool g_bGameInit = false;
|
||||||
bool bGameInit = false;
|
|
||||||
SourceHook::List<GameDllInfo *> gamedll_list;
|
|
||||||
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
||||||
SourceHook::CallClass<ICvar> *g_CvarPatch;
|
SourceHook::CallClass<ICvar> *g_CvarPatch;
|
||||||
int g_GameDllVersion = 0;
|
int g_GameDllVersion = 0;
|
||||||
const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001";
|
static const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001";
|
||||||
const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002";
|
static const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002";
|
||||||
const char GAMEINFO_PATH[] = "|gameinfo_path|";
|
static const char GAMEINFO_PATH[] = "|gameinfo_path|";
|
||||||
IFileSystem *baseFs = NULL;
|
IFileSystem *baseFs = NULL;
|
||||||
bool g_bLevelChanged = false;
|
bool g_bLevelChanged = false;
|
||||||
IServerPluginCallbacks *g_pRealVspCallbacks = &g_VspListener;
|
IServerPluginCallbacks *g_pRealVspCallbacks = &g_VspListener;
|
||||||
|
|
||||||
void ClearGamedllList();
|
|
||||||
|
|
||||||
/* Helper Macro */
|
|
||||||
#define IFACE_MACRO(orig,nam) \
|
|
||||||
CPluginManager::CPlugin *pl; \
|
|
||||||
SourceHook::List<CPluginEventHandler>::iterator event; \
|
|
||||||
IMetamodListener *api; \
|
|
||||||
int mret = 0; \
|
|
||||||
void *val = NULL; \
|
|
||||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
|
||||||
pl = (*iter); \
|
|
||||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
|
||||||
api = (*event).event; \
|
|
||||||
mret = IFACE_FAILED; \
|
|
||||||
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
|
|
||||||
if (ret) *ret = mret; \
|
|
||||||
return val; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return (orig)(iface, ret);
|
|
||||||
|
|
||||||
#define ITER_EVENT(evn, args) \
|
#define ITER_EVENT(evn, args) \
|
||||||
CPluginManager::CPlugin *pl; \
|
CPluginManager::CPlugin *pl; \
|
||||||
SourceHook::List<CPluginEventHandler>::iterator event; \
|
SourceHook::List<CPluginEventHandler>::iterator event; \
|
||||||
@ -111,18 +90,17 @@ void ClearGamedllList();
|
|||||||
/* Initialize everything here */
|
/* Initialize everything here */
|
||||||
void InitMainStates()
|
void InitMainStates()
|
||||||
{
|
{
|
||||||
char full_path[PATH_SIZE] = {0};
|
|
||||||
GetFileOfAddress((void *)g_GameDll.factory, full_path, sizeof(full_path));
|
|
||||||
g_BinPath.assign(full_path);
|
|
||||||
|
|
||||||
/* Like Metamod, reload plugins at the end of the map.
|
/* Like Metamod, reload plugins at the end of the map.
|
||||||
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
|
* This is so plugins can hook everything on load, BUT, new plugins will be reloaded
|
||||||
* if the server is shut down (silly, but rare case).
|
* if the server is shut down (silly, but rare case).
|
||||||
*/
|
*/
|
||||||
bInFirstLevel = true;
|
bInFirstLevel = true;
|
||||||
|
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit, false);
|
char smm_path[PATH_SIZE];
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLInit, g_GameDll.pGameDLL, DLLInit_Post, true);
|
const char *game_dir = CommandLine()->ParmValue("-game", "hl2");
|
||||||
|
abspath(smm_path, game_dir);
|
||||||
|
g_ModPath.assign(smm_path);
|
||||||
|
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLShutdown, g_GameDll.pGameDLL, DLLShutdown_handler, false);
|
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, DLLShutdown, g_GameDll.pGameDLL, DLLShutdown_handler, false);
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
|
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
|
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
|
||||||
@ -225,16 +203,20 @@ bool StartupMetamod(CreateInterfaceFn engineFactory, bool bWaitForGameInit)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
void LoadAsGameDLL(const gamedll_bridge_info *info)
|
||||||
{
|
{
|
||||||
g_Engine.engineFactory = engineFactory;
|
g_Engine.engineFactory = (CreateInterfaceFn)info->engineFactory;
|
||||||
g_Engine.fileSystemFactory = filesystemFactory;
|
g_Engine.fileSystemFactory = (CreateInterfaceFn)info->fsFactory;
|
||||||
g_Engine.physicsFactory = physicsFactory;
|
g_Engine.physicsFactory = (CreateInterfaceFn)info->physicsFactory;
|
||||||
g_Engine.pGlobals = pGlobals;
|
g_Engine.pGlobals = (CGlobalVars*)info->pGlobals;
|
||||||
|
g_GameDll.loaded = true;
|
||||||
|
g_GameDll.factory = (CreateInterfaceFn)info->gsFactory;
|
||||||
|
g_GameDll.pGameDLL = (IServerGameDLL*)info->isgd;
|
||||||
|
g_GameDllVersion = info->dllVersion;
|
||||||
|
|
||||||
StartupMetamod(engineFactory, false);
|
InitMainStates();
|
||||||
|
|
||||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
StartupMetamod(g_Engine.engineFactory, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory)
|
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory)
|
||||||
@ -254,7 +236,6 @@ bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn se
|
|||||||
|
|
||||||
/* Now find the server */
|
/* Now find the server */
|
||||||
g_GameDll.factory = serverFactory;
|
g_GameDll.factory = serverFactory;
|
||||||
g_GameDll.lib = NULL;
|
|
||||||
|
|
||||||
char gamedll_iface[] = "ServerGameDLL000";
|
char gamedll_iface[] = "ServerGameDLL000";
|
||||||
for (unsigned int i = 3; i <= 50; i++)
|
for (unsigned int i = 3; i <= 50; i++)
|
||||||
@ -285,15 +266,6 @@ bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char smm_path[PATH_SIZE];
|
|
||||||
const char *game_dir;
|
|
||||||
GetFileOfAddress((void *)AlternatelyLoadMetamod, smm_path, sizeof(smm_path));
|
|
||||||
g_SmmPath.assign(smm_path);
|
|
||||||
|
|
||||||
game_dir = CommandLine()->ParmValue("-game", "hl2");
|
|
||||||
abspath(smm_path, game_dir);
|
|
||||||
g_ModPath.assign(smm_path);
|
|
||||||
|
|
||||||
InitMainStates();
|
InitMainStates();
|
||||||
|
|
||||||
if (!StartupMetamod(ifaceFactory, true))
|
if (!StartupMetamod(ifaceFactory, true))
|
||||||
@ -308,7 +280,7 @@ bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn se
|
|||||||
|
|
||||||
bool GameInit_handler()
|
bool GameInit_handler()
|
||||||
{
|
{
|
||||||
if (bGameInit)
|
if (g_bGameInit)
|
||||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||||
|
|
||||||
if (g_SmmAPI.VSPEnabled() && !g_bIsBridgedAsVsp)
|
if (g_SmmAPI.VSPEnabled() && !g_bIsBridgedAsVsp)
|
||||||
@ -317,286 +289,11 @@ bool GameInit_handler()
|
|||||||
if (g_bIsBridgedAsVsp)
|
if (g_bIsBridgedAsVsp)
|
||||||
DoInitialPluginLoads();
|
DoInitialPluginLoads();
|
||||||
|
|
||||||
bGameInit = true;
|
g_bGameInit = true;
|
||||||
|
|
||||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DLLInit_Post(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
|
||||||
{
|
|
||||||
g_PluginMngr.SetAllLoaded();
|
|
||||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is where the magic happens */
|
|
||||||
SMM_API void *CreateInterface(const char *iface, int *ret)
|
|
||||||
{
|
|
||||||
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
|
|
||||||
if (strcmp(iface, PLAPI_NAME) == 0)
|
|
||||||
{
|
|
||||||
Warning("Do not try loading Metamod:Source as a Metamod:Source plugin");
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
*ret = IFACE_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We check these separately because we can't reply
|
|
||||||
* unless our interface version really matches.
|
|
||||||
*/
|
|
||||||
if (!g_bIsBridgedAsVsp &&
|
|
||||||
(strcmp(iface, VSPIFACE_002) == 0 ||
|
|
||||||
strcmp(iface, VSPIFACE_001) == 0))
|
|
||||||
{
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
*ret = IFACE_OK;
|
|
||||||
}
|
|
||||||
return &g_VspListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're a VSP, bypass this by default */
|
|
||||||
if (g_bIsBridgedAsVsp)
|
|
||||||
{
|
|
||||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gParsedGameInfo)
|
|
||||||
{
|
|
||||||
gParsedGameInfo = true;
|
|
||||||
const char *gameDir = NULL;
|
|
||||||
char gamePath[PATH_SIZE];
|
|
||||||
char smmPath[PATH_SIZE];
|
|
||||||
|
|
||||||
/* Get path to SourceMM DLL */
|
|
||||||
if (!GetFileOfAddress((void *)CreateInterface, smmPath, sizeof(smmPath)))
|
|
||||||
{
|
|
||||||
Error("GetFileOfAddress() failed! Metamod cannot load.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_SmmPath.assign(smmPath);
|
|
||||||
|
|
||||||
/* Get value of -game from command line, defaulting to hl2 as engine seems to do */
|
|
||||||
gameDir = CommandLine()->ParmValue("-game", "hl2");
|
|
||||||
|
|
||||||
/* Get absolute path */
|
|
||||||
abspath(gamePath, gameDir);
|
|
||||||
g_ModPath.assign(gamePath);
|
|
||||||
|
|
||||||
char tempPath[PATH_SIZE];
|
|
||||||
|
|
||||||
/* Path to gameinfo.txt */
|
|
||||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s", g_ModPath.c_str(), "gameinfo.txt");
|
|
||||||
|
|
||||||
FILE *fp = fopen(tempPath, "rt");
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
Error("Unable to open gameinfo.txt! Metamod cannot load.\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[255];
|
|
||||||
char key[128], val[128];
|
|
||||||
size_t len = 0;
|
|
||||||
bool search = false;
|
|
||||||
bool gamebin = false;
|
|
||||||
char *ptr;
|
|
||||||
const char *lptr;
|
|
||||||
char curPath[PATH_SIZE];
|
|
||||||
|
|
||||||
getcwd(curPath, PATH_SIZE);
|
|
||||||
|
|
||||||
while (!feof(fp))
|
|
||||||
{
|
|
||||||
buffer[0] = '\0';
|
|
||||||
fgets(buffer, sizeof(buffer), fp);
|
|
||||||
len = strlen(buffer);
|
|
||||||
if (buffer[len-1] == '\n')
|
|
||||||
buffer[--len] = '\0';
|
|
||||||
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 = g_ModPath.c_str();
|
|
||||||
} else {
|
|
||||||
ptr = val;
|
|
||||||
lptr = curPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, ptr, SERVER_DLL);
|
|
||||||
} else if (!ptr[0]) {
|
|
||||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s", lptr, "bin", SERVER_DLL);
|
|
||||||
} else {
|
|
||||||
g_SmmAPI.PathFormat(tempPath, PATH_SIZE, "%s/%s/%s/%s", lptr, ptr, "bin", SERVER_DLL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If not path to SourceMM... */
|
|
||||||
if (!UTIL_PathCmp(smmPath, tempPath))
|
|
||||||
{
|
|
||||||
FILE *fp = fopen(tempPath, "rb");
|
|
||||||
if (!fp)
|
|
||||||
continue;
|
|
||||||
//:TODO: Optimize this a bit!
|
|
||||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
|
||||||
GameDllInfo *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(tempPath, buffer))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
continue;
|
|
||||||
fclose(fp);
|
|
||||||
HINSTANCE gamedll = dlmount(tempPath);
|
|
||||||
if (gamedll == NULL)
|
|
||||||
continue;
|
|
||||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(gamedll, "CreateInterface");
|
|
||||||
if (fn == NULL)
|
|
||||||
{
|
|
||||||
dlclose(gamedll);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GameDllInfo *pInfo = new GameDllInfo;
|
|
||||||
pInfo->factory = fn;
|
|
||||||
pInfo->lib = gamedll;
|
|
||||||
pInfo->loaded = true;
|
|
||||||
pInfo->pGameDLL = NULL;
|
|
||||||
gamedll_list.push_back(pInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_GameDll.loaded)
|
|
||||||
{
|
|
||||||
const char *str = "ServerGameDLL";
|
|
||||||
size_t len = strlen(str);
|
|
||||||
|
|
||||||
if (strncmp(iface, str, len) == 0)
|
|
||||||
{
|
|
||||||
/* This is the interface we want! Right now we support versions 3 through 8 */
|
|
||||||
g_GameDllVersion = atoi(&(iface[len]));
|
|
||||||
int sizeTooBig = 0; //rename this to sizeWrong in the future!
|
|
||||||
if (g_GameDllVersion < MIN_GAMEDLL_VERSION || g_GameDllVersion > MAX_GAMEDLL_VERSION)
|
|
||||||
{
|
|
||||||
/* Maybe this will get used in the future */
|
|
||||||
sizeTooBig = g_GameDllVersion;
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
*ret = IFACE_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
|
||||||
GameDllInfo *pInfo = NULL;
|
|
||||||
void *ptr;
|
|
||||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
|
||||||
{
|
|
||||||
pInfo = (*iter);
|
|
||||||
ptr = (pInfo->factory)(iface, ret);
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
/* This is our GameDLL. Unload the others. */
|
|
||||||
gamedll_list.erase(iter);
|
|
||||||
ClearGamedllList();
|
|
||||||
pInfo->pGameDLL = static_cast<IServerGameDLL *>(ptr);
|
|
||||||
g_GameDll = *pInfo;
|
|
||||||
delete pInfo;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (g_GameDll.loaded)
|
|
||||||
{
|
|
||||||
if (sizeTooBig)
|
|
||||||
{
|
|
||||||
Error("This mod version requires a SourceMM update (ServerGameDLL%03d)!\n", sizeTooBig);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
*ret = IFACE_FAILED;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
InitMainStates();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sizeTooBig = 0;
|
|
||||||
if (ret)
|
|
||||||
*ret = IFACE_FAILED;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* wtf do we do... */
|
|
||||||
/* :TODO: .. something a bit more intelligent? */
|
|
||||||
Error("Engine requested unknown interface before GameDLL was known!\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We use this interface for responding to the meta client command */
|
|
||||||
if (strncmp(iface, "ServerGameClients", 17) == 0)
|
|
||||||
{
|
|
||||||
void *ptr = (g_GameDll.factory)(iface, ret);
|
|
||||||
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we got here, there's definitely a GameDLL */
|
|
||||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearGamedllList()
|
|
||||||
{
|
|
||||||
SourceHook::List<GameDllInfo *>::iterator iter;
|
|
||||||
|
|
||||||
GameDllInfo *pInfo;
|
|
||||||
for (iter=gamedll_list.begin(); iter!=gamedll_list.end(); iter++)
|
|
||||||
{
|
|
||||||
pInfo = (*iter);
|
|
||||||
dlclose(pInfo->lib);
|
|
||||||
delete pInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
gamedll_list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadMetamod(bool shutting_down)
|
void UnloadMetamod(bool shutting_down)
|
||||||
{
|
{
|
||||||
/* Unload plugins */
|
/* Unload plugins */
|
||||||
@ -617,12 +314,6 @@ void UnloadMetamod(bool shutting_down)
|
|||||||
g_CvarPatch = NULL;
|
g_CvarPatch = NULL;
|
||||||
|
|
||||||
g_SourceHook.CompleteShutdown();
|
g_SourceHook.CompleteShutdown();
|
||||||
|
|
||||||
if (g_GameDll.lib && g_GameDll.loaded)
|
|
||||||
{
|
|
||||||
dlclose(g_GameDll.lib);
|
|
||||||
}
|
|
||||||
memset(&g_GameDll, 0, sizeof(GameDllInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DLLShutdown_handler()
|
void DLLShutdown_handler()
|
||||||
@ -945,31 +636,6 @@ int LoadPluginsFromFile(const char *_file)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
|
||||||
* the engine's real engineFactory.
|
|
||||||
*/
|
|
||||||
void *EngineFactory(const char *iface, int *ret)
|
|
||||||
{
|
|
||||||
IFACE_MACRO(g_Engine.engineFactory, Engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
|
||||||
* the engine's real physicsFactory.
|
|
||||||
*/
|
|
||||||
void *PhysicsFactory(const char *iface, int *ret)
|
|
||||||
{
|
|
||||||
IFACE_MACRO(g_Engine.physicsFactory, Physics);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
|
||||||
* the engine's real fileSystemFactory.
|
|
||||||
*/
|
|
||||||
void *FileSystemFactory(const char *iface, int *ret)
|
|
||||||
{
|
|
||||||
IFACE_MACRO(g_Engine.fileSystemFactory, FileSystem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogMessage(const char *msg, ...)
|
void LogMessage(const char *msg, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "oslink.h"
|
#include "oslink.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "loader_bridge.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Versioning
|
* Versioning
|
||||||
@ -65,7 +66,6 @@ void LogMessage(const char *msg, ...);
|
|||||||
struct GameDllInfo
|
struct GameDllInfo
|
||||||
{
|
{
|
||||||
bool loaded;
|
bool loaded;
|
||||||
HINSTANCE lib;
|
|
||||||
CreateInterfaceFn factory;
|
CreateInterfaceFn factory;
|
||||||
IServerGameDLL *pGameDLL;
|
IServerGameDLL *pGameDLL;
|
||||||
IServerGameClients *pGameClients;
|
IServerGameClients *pGameClients;
|
||||||
@ -105,12 +105,6 @@ extern SourceHook::CSourceHookImpl g_SourceHook;
|
|||||||
/** @brief Mod path (important!)*/
|
/** @brief Mod path (important!)*/
|
||||||
extern SourceHook::String g_ModPath;
|
extern SourceHook::String g_ModPath;
|
||||||
|
|
||||||
/** @brief Path to server binary */
|
|
||||||
extern SourceHook::String g_BinPath;
|
|
||||||
|
|
||||||
/** @brief Path to SourceMM binary */
|
|
||||||
extern SourceHook::String g_SmmPath;
|
|
||||||
|
|
||||||
/** @brief Global variable for SourceHook macros */
|
/** @brief Global variable for SourceHook macros */
|
||||||
extern SourceHook::ISourceHook *g_SHPtr;
|
extern SourceHook::ISourceHook *g_SHPtr;
|
||||||
|
|
||||||
@ -120,7 +114,7 @@ extern PluginId g_PLID;
|
|||||||
/** @brief ServerGameDLL version that is currently loaded */
|
/** @brief ServerGameDLL version that is currently loaded */
|
||||||
extern int g_GameDllVersion;
|
extern int g_GameDllVersion;
|
||||||
|
|
||||||
extern bool bGameInit;
|
extern bool g_bGameInit;
|
||||||
extern bool g_bLevelChanged;
|
extern bool g_bLevelChanged;
|
||||||
|
|
||||||
void UnloadMetamod(bool shutting_down);
|
void UnloadMetamod(bool shutting_down);
|
||||||
@ -128,7 +122,10 @@ void UnloadMetamod(bool shutting_down);
|
|||||||
/** @brief Global CallClass for IServerGameDLL */
|
/** @brief Global CallClass for IServerGameDLL */
|
||||||
extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
||||||
|
|
||||||
|
void LoadAsGameDLL(const gamedll_bridge_info *info);
|
||||||
|
|
||||||
/** @brief Global CallClass for ICvar */
|
/** @brief Global CallClass for ICvar */
|
||||||
extern SourceHook::CallClass<ICvar> *g_CvarPatch;
|
extern SourceHook::CallClass<ICvar> *g_CvarPatch;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMM_H
|
#endif //_INCLUDE_SOURCEMM_H
|
||||||
|
|
||||||
|
@ -82,91 +82,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;
|
||||||
|
@ -26,11 +26,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.
|
||||||
*/
|
*/
|
||||||
@ -41,11 +36,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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user