1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-01-31 20:52:18 +01:00

Properly implementing GameDLL unloading.

This commit is contained in:
David Anderson 2008-11-23 21:50:17 -06:00
parent 97b323a583
commit 08f2df2d78
4 changed files with 80 additions and 22 deletions

View File

@ -34,8 +34,17 @@ public:
LoadAsGameDLL(info);
return true;
}
virtual void DLLInit_Post()
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)
@ -53,6 +62,7 @@ public:
}
virtual void Unload()
{
UnloadMetamod(true);
}
};

View File

@ -32,13 +32,11 @@ using namespace SourceMM;
#undef CommandLine
DLL_IMPORT ICommandLine *CommandLine();
SH_DECL_HOOK0_void(IServerGameDLL, DLLShutdown, 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_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
SH_DECL_HOOK0(IServerGameDLL, GameInit, SH_NOATTRIB, false, bool);
void DLLShutdown_handler();
void LevelShutdown_handler();
bool LevelInit_handler(char const *pMapName,
char const *pMapEntities,
@ -101,7 +99,6 @@ void InitMainStates()
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, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
@ -304,8 +301,6 @@ void UnloadMetamod(bool shutting_down)
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
g_SMConVarAccessor.MarkCommandsAsGameDLL();
g_Engine.icvar->UnlinkVariables(FCVAR_GAMEDLL);
SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)();
}
SH_RELEASE_CALLCLASS(g_GameDllPatch);
@ -316,12 +311,6 @@ void UnloadMetamod(bool shutting_down)
g_SourceHook.CompleteShutdown();
}
void DLLShutdown_handler()
{
UnloadMetamod(true);
RETURN_META(MRES_SUPERCEDE);
}
void LoadFromVDF(const char *file)
{
PluginId id;

View File

@ -25,6 +25,7 @@ static void *gamedll_lib = NULL;
static IServerGameDLL *gamedll_iface = NULL;
static QueryValveInterface gamedll_qvi = NULL;
static int gamedll_version = 0;
static int isgd_shutdown_index = -1;
#if defined _WIN32
#define TIER0_NAME "bin\\tier0.dll"
@ -213,7 +214,11 @@ mm_FreeCachedLibraries()
static void
mm_PatchDllInit(bool patch);
static void *isgd_orig_call = NULL;
static void
mm_PatchDllShutdown();
static void *isgd_orig_init = NULL;
static void *isgd_orig_shutdown = NULL;
class VEmptyClass
{
@ -286,7 +291,7 @@ public:
#if defined _WIN32
void *addr;
} u;
u.addr = isgd_orig_call;
u.addr = isgd_orig_init;
#else
struct
{
@ -294,7 +299,7 @@ public:
intptr_t adjustor;
} s;
} u;
u.s.addr = isgd_orig_call;
u.s.addr = isgd_orig_init;
u.s.adjustor = 0;
#endif
result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory,
@ -316,13 +321,47 @@ public:
}
else if (gamedll_bridge != NULL)
{
gamedll_bridge->DLLInit_Post();
gamedll_bridge->DLLInit_Post(&isgd_shutdown_index);
assert(isgd_shutdown_index != -1);
mm_PatchDllShutdown();
}
mm_PatchDllInit(false);
return result;
}
virtual void DLLShutdown()
{
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;
}
};
static IServerGameDLL isgd_thunk;
@ -349,18 +388,38 @@ mm_PatchDllInit(bool patch)
if (patch)
{
assert(isgd_orig_call == NULL);
isgd_orig_call = vtable_dest[mfp.vtblindex];
assert(isgd_orig_init == NULL);
isgd_orig_init = 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;
assert(isgd_orig_init != NULL);
vtable_dest[mfp.vtblindex] = isgd_orig_init;
isgd_orig_init = NULL;
}
}
static void
mm_PatchDllShutdown()
{
void **vtable_src;
void **vtable_dest;
SourceHook::MemFuncInfo mfp;
mfp.isVirtual = false;
SourceHook::GetFuncInfo(&IServerGameDLL::DLLShutdown, mfp);
assert(mfp.isVirtual);
assert(mfp.thisptroffs == 0);
assert(mfp.vtbloffs == 0);
vtable_src = (void **)*(void **)&isgd_thunk;
vtable_dest = (void **)*(void **)gamedll_iface;
isgd_orig_shutdown = vtable_dest[isgd_shutdown_index];
vtable_dest[isgd_shutdown_index] = vtable_src[mfp.vtblindex];
}
static void
mm_PrepForGameLoad()
{

View File

@ -35,7 +35,7 @@ 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 DLLInit_Post(int *isgdUnload) = 0;
virtual void *QueryInterface(const char *name, int *ret) = 0;
virtual void Unload() = 0;
};