virtual void Unload() { if (vsp_bridge == NULL) return; vsp_bridge->Unload(); if (gamedll_bridge == NULL) { mm_UnloadMetamodLibrary(); } }
virtual bool DLLInit(QueryValveInterface engineFactory, QueryValveInterface physicsFactory, QueryValveInterface fileSystemFactory, void *pGlobals) { mm_backend = mm_DetermineBackend(engineFactory, gamedll_qvi, game_name); char error[255]; if (mm_backend == MMBackend_UNKNOWN) { mm_LogFatal("Could not detect engine version"); } else { if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) { mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); } else { typedef IGameDllBridge *(*GetGameDllBridge)(); GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge"); if (get_bridge == NULL) { mm_UnloadMetamodLibrary(); mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", mm_backend); } else { gamedll_bridge = get_bridge(); } } } if (gamedll_bridge) { gamedll_bridge_info info; info.engineFactory = (QueryValveInterface)engineFactory; info.physicsFactory = (QueryValveInterface)physicsFactory; info.fsFactory = (QueryValveInterface)fileSystemFactory; info.pGlobals = pGlobals; info.dllVersion = gamedll_version; info.isgd = gamedll_iface; info.gsFactory = gamedll_qvi; info.vsp_listener_path = mm_path; strcpy(error, "Unknown error"); if (!gamedll_bridge->DLLInit_Pre(&info, error, sizeof(error))) { gamedll_bridge = NULL; mm_UnloadMetamodLibrary(); mm_LogFatal("Unknown error loading Metamod for engine %d: %s", mm_backend, error); } } /* Call the original */ bool result; { union { bool (VEmptyClass::*mfpnew)(QueryValveInterface engineFactory, QueryValveInterface physicsFactory, QueryValveInterface fileSystemFactory, void *pGlobals); #if defined _WIN32 void *addr; } u; u.addr = isgd_orig_init; #else struct { void *addr; intptr_t adjustor; } s; } u; u.s.addr = isgd_orig_init; u.s.adjustor = 0; #endif result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory, physicsFactory, fileSystemFactory, pGlobals); }
virtual bool Load(QueryValveInterface engineFactory, QueryValveInterface gsFactory) { if (!load_allowed) return false; load_allowed = false; /* Backend should already filled in if loaded as gamedll */ if (gamedll_bridge == NULL) { mm_GetGameName(game_name, sizeof(game_name)); mm_backend = mm_DetermineBackend(engineFactory, gsFactory, game_name); } if (mm_backend == MMBackend_UNKNOWN) { mm_LogFatal("Could not detect engine version"); return false; } void **this_vtable; this_vtable = (void **)*(void **)this; if (mm_backend != MMBackend_Episode1 && mm_backend != MMBackend_DarkMessiah) { /* We need to insert the right type of call into this vtable */ void **vtable_src; IRandomThings sample; SourceHook::MemFuncInfo mfp_dest, mfp_src; mfp_dest.isVirtual = false; mfp_src.isVirtual = false; SourceHook::GetFuncInfo(&ServerPlugin::ClientCommand, mfp_dest); SourceHook::GetFuncInfo(&IRandomThings::ClientCommand, mfp_src); assert(mfp_dest.isVirtual); assert(mfp_dest.thisptroffs == 0); assert(mfp_dest.vtbloffs == 0); assert(mfp_src.isVirtual); assert(mfp_src.thisptroffs == 0); assert(mfp_src.vtbloffs == 0); vtable_src = (void **)*(void **)&sample; SourceHook::SetMemAccess(&this_vtable[mfp_dest.vtblindex], sizeof(void*), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); this_vtable[mfp_dest.vtblindex] = vtable_src[mfp_src.vtblindex]; } /* AS inserted ClientFullyConnect into vtable, so move entries up on older engines */ if (mm_backend != MMBackend_AlienSwarm && mm_backend != MMBackend_Portal2 && mm_backend != MMBackend_Blade && mm_backend != MMBackend_Insurgency && mm_backend != MMBackend_DOI && mm_backend != MMBackend_CSGO && mm_backend != MMBackend_DOTA) { SourceHook::MemFuncInfo mfp_fconnect; mfp_fconnect.isVirtual = false; SourceHook::GetFuncInfo(&ServerPlugin::ClientFullyConnect, mfp_fconnect); assert(mfp_fconnect.isVirtual); assert(mfp_fconnect.thisptroffs == 0); assert(mfp_fconnect.vtbloffs == 0); /* Shifting ClientDisconnect through OnQueryCvarValueFinished up into slot for * ClientFullyConnect (8 entries) */ SourceHook::SetMemAccess(&this_vtable[mfp_fconnect.vtblindex], sizeof(void *) * 8, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); memmove(&this_vtable[mfp_fconnect.vtblindex], &this_vtable[mfp_fconnect.vtblindex + 1], sizeof(void *) * 8); } char error[255]; if (gamedll_bridge == NULL) { if (!mm_LoadMetamodLibrary(mm_backend, error, sizeof(error))) { mm_LogFatal("Detected engine %d but could not load: %s", mm_backend, error); return false; } } typedef IVspBridge *(*GetVspBridge)(); GetVspBridge get_bridge = (GetVspBridge)mm_GetProcAddress("GetVspBridge"); if (get_bridge == NULL) { if (gamedll_bridge == NULL) { mm_UnloadMetamodLibrary(); } mm_LogFatal("Detected engine %d but could not find GetVspBridge callback", mm_backend); return false; } vsp_bridge = get_bridge(); vsp_bridge_info info; info.engineFactory = engineFactory; info.gsFactory = gsFactory; info.vsp_callbacks = (IServerPluginCallbacks*)this; info.vsp_version = vsp_version; strcpy(error, "Unknown error"); if (!vsp_bridge->Load(&info, error, sizeof(error))) { vsp_bridge = NULL; if (gamedll_bridge == NULL) { mm_UnloadMetamodLibrary(); } mm_LogFatal("Unknown error loading Metamod for engine %d: %s", mm_backend, error); return false; } return true; }