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:
parent
97b323a583
commit
08f2df2d78
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user