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);
|
LoadAsGameDLL(info);
|
||||||
return true;
|
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();
|
g_PluginMngr.SetAllLoaded();
|
||||||
}
|
}
|
||||||
virtual void *QueryInterface(const char *iface, int *ret)
|
virtual void *QueryInterface(const char *iface, int *ret)
|
||||||
@ -53,6 +62,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void Unload()
|
virtual void Unload()
|
||||||
{
|
{
|
||||||
|
UnloadMetamod(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,13 +32,11 @@ using namespace SourceMM;
|
|||||||
#undef CommandLine
|
#undef CommandLine
|
||||||
DLL_IMPORT ICommandLine *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_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);
|
||||||
|
|
||||||
void DLLShutdown_handler();
|
|
||||||
void LevelShutdown_handler();
|
void LevelShutdown_handler();
|
||||||
bool LevelInit_handler(char const *pMapName,
|
bool LevelInit_handler(char const *pMapName,
|
||||||
char const *pMapEntities,
|
char const *pMapEntities,
|
||||||
@ -101,7 +99,6 @@ void InitMainStates()
|
|||||||
abspath(smm_path, game_dir);
|
abspath(smm_path, game_dir);
|
||||||
g_ModPath.assign(smm_path);
|
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, 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);
|
||||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
|
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 */
|
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
|
||||||
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
||||||
g_Engine.icvar->UnlinkVariables(FCVAR_GAMEDLL);
|
g_Engine.icvar->UnlinkVariables(FCVAR_GAMEDLL);
|
||||||
|
|
||||||
SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SH_RELEASE_CALLCLASS(g_GameDllPatch);
|
SH_RELEASE_CALLCLASS(g_GameDllPatch);
|
||||||
@ -316,12 +311,6 @@ void UnloadMetamod(bool shutting_down)
|
|||||||
g_SourceHook.CompleteShutdown();
|
g_SourceHook.CompleteShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DLLShutdown_handler()
|
|
||||||
{
|
|
||||||
UnloadMetamod(true);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadFromVDF(const char *file)
|
void LoadFromVDF(const char *file)
|
||||||
{
|
{
|
||||||
PluginId id;
|
PluginId id;
|
||||||
|
@ -25,6 +25,7 @@ static void *gamedll_lib = NULL;
|
|||||||
static IServerGameDLL *gamedll_iface = NULL;
|
static IServerGameDLL *gamedll_iface = NULL;
|
||||||
static QueryValveInterface gamedll_qvi = NULL;
|
static QueryValveInterface gamedll_qvi = NULL;
|
||||||
static int gamedll_version = 0;
|
static int gamedll_version = 0;
|
||||||
|
static int isgd_shutdown_index = -1;
|
||||||
|
|
||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
#define TIER0_NAME "bin\\tier0.dll"
|
#define TIER0_NAME "bin\\tier0.dll"
|
||||||
@ -213,7 +214,11 @@ mm_FreeCachedLibraries()
|
|||||||
static void
|
static void
|
||||||
mm_PatchDllInit(bool patch);
|
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
|
class VEmptyClass
|
||||||
{
|
{
|
||||||
@ -286,7 +291,7 @@ public:
|
|||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
void *addr;
|
void *addr;
|
||||||
} u;
|
} u;
|
||||||
u.addr = isgd_orig_call;
|
u.addr = isgd_orig_init;
|
||||||
#else
|
#else
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -294,7 +299,7 @@ public:
|
|||||||
intptr_t adjustor;
|
intptr_t adjustor;
|
||||||
} s;
|
} s;
|
||||||
} u;
|
} u;
|
||||||
u.s.addr = isgd_orig_call;
|
u.s.addr = isgd_orig_init;
|
||||||
u.s.adjustor = 0;
|
u.s.adjustor = 0;
|
||||||
#endif
|
#endif
|
||||||
result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory,
|
result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory,
|
||||||
@ -316,13 +321,47 @@ public:
|
|||||||
}
|
}
|
||||||
else if (gamedll_bridge != NULL)
|
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);
|
mm_PatchDllInit(false);
|
||||||
|
|
||||||
return result;
|
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;
|
static IServerGameDLL isgd_thunk;
|
||||||
@ -349,18 +388,38 @@ mm_PatchDllInit(bool patch)
|
|||||||
|
|
||||||
if (patch)
|
if (patch)
|
||||||
{
|
{
|
||||||
assert(isgd_orig_call == NULL);
|
assert(isgd_orig_init == NULL);
|
||||||
isgd_orig_call = vtable_dest[mfp.vtblindex];
|
isgd_orig_init = vtable_dest[mfp.vtblindex];
|
||||||
vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex];
|
vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(isgd_orig_call != NULL);
|
assert(isgd_orig_init != NULL);
|
||||||
vtable_dest[mfp.vtblindex] = isgd_orig_call;
|
vtable_dest[mfp.vtblindex] = isgd_orig_init;
|
||||||
isgd_orig_call = NULL;
|
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
|
static void
|
||||||
mm_PrepForGameLoad()
|
mm_PrepForGameLoad()
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ class IGameDllBridge
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength) = 0;
|
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 *QueryInterface(const char *name, int *ret) = 0;
|
||||||
virtual void Unload() = 0;
|
virtual void Unload() = 0;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user