From a4afb6714f67c029310c0853ff47fdef354e2e72 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 26 Dec 2022 14:29:53 +0000 Subject: Fix deferred init for Portal 2 compatibility Thanks Bill for figuring out what the problem was. --- src/sst.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) (limited to 'src/sst.c') diff --git a/src/sst.c b/src/sst.c index d159c8e..788a81d 100644 --- a/src/sst.c +++ b/src/sst.c @@ -211,15 +211,17 @@ static void do_featureinit(void) { } } -static void *vgui; -typedef void (*VCALLCONV VGuiConnect_func)(void); +typedef void (*VCALLCONV VGuiConnect_func)(void *this); static VGuiConnect_func orig_VGuiConnect; -static void VCALLCONV hook_VGuiConnect(void) { - orig_VGuiConnect(); +static void VCALLCONV hook_VGuiConnect(void *this) { + orig_VGuiConnect(this); do_featureinit(); - unhook_vtable(*(void ***)vgui, vtidx_VGuiConnect, (void *)orig_VGuiConnect); + unhook_vtable(*(void ***)vgui, vtidx_VGuiConnect, + (void *)orig_VGuiConnect); } +DECL_VFUNC_DYN(bool, VGuiIsInitialized) + // --- Magical deferred load order hack nonsense! --- // The engine loads VDF plugins basically right after server.dll, but long // before most other stuff, which makes hooking certain other stuff a pain. We @@ -227,23 +229,22 @@ static void VCALLCONV hook_VGuiConnect(void) { // in before config.cfg, which is needed for any kind of configuration to work // correctly. // -// So here, we hook CEngineVGui::Connect() which is pretty much the last thing -// that gets called on init, and defer feature init till afterwards. That allows -// us to touch pretty much any engine stuff without worrying about load order -// nonsense. -// -// In do_load() below, we check to see whether we're loading early by checking -// whether gameui.dll is loaded yet; this is one of several possible arbitrary -// checks. If it's loaded already, we assume we're getting loaded late via the -// console and just init everything immediately. +// So here, we hook CEngineVGui::Connect() which is one the very last things +// to get called on startup, and use that hook to defer feature init till after +// most of the rest of the game is up and running. That allows us to touch +// pretty much any engine stuff without worrying about load order nonsense. // // Route credit to Bill for helping figure a lot of this out - mike -static void deferinit(void) { - vgui = factory_engine("VEngineVGui001", 0); +static bool deferinit(void) { if (!vgui) { - errmsg_warnx("couldn't get VEngineVGui for deferred feature setup"); + errmsg_warnx("can't use VEngineVGui for deferred feature setup"); goto e; } + // Arbitrary check to infer whether we've been early- or late-loaded. + // We used to just see whether gameui.dll/libgameui.so was loaded, but + // Portal 2 does away with the separate gameui library, so now we just call + // CEngineVGui::IsInitialized() which works everywhere. + if (VGuiIsInitialized(vgui)) return false; if (!os_mprot(*(void ***)vgui + vtidx_VGuiConnect, sizeof(void *), PAGE_READWRITE)) { errmsg_warnsys("couldn't make CEngineVGui vtable writable for deferred " @@ -252,11 +253,11 @@ static void deferinit(void) { } orig_VGuiConnect = (VGuiConnect_func)hook_vtable(*(void ***)vgui, vtidx_VGuiConnect, (void *)&hook_VGuiConnect); - return; + return true; e: con_warn("!!! SOME FEATURES MAY BE BROKEN !!!\n"); - // I think this is the lesser of two evils! Unlikely to happen anyway. - do_featureinit(); + // Lesser of two evils: just init features now. Unlikely to happen anyway. + return false; } static bool do_load(ifacefactory enginef, ifacefactory serverf) { @@ -329,14 +330,7 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) { } } -#ifdef _WIN32 - bool isvdf = !GetModuleHandleW(L"gameui.dll"); -#else - void *gameuilib = dlopen("bin/libgameui.so", RTLD_NOW | RLTD_NOLOAD); - bool isvdf = !gameuilib; - if (gameuilib) dlclose(gameuilib); -#endif - if (isvdf) deferinit(); else do_featureinit(); + if (!deferinit()) do_featureinit(); return true; } -- cgit v1.2.3