diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index ae60e192..4282a971 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -46,7 +46,7 @@ SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String}; typedef List ConVarList; -ConVarManager::ConVarManager() : m_ConVarType(0), m_VSPIface(NULL), m_CanQueryConVars(false) +ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false) { #if PLAPI_VERSION < 12 m_IgnoreHandle = false; @@ -74,11 +74,15 @@ ConVarManager::~ConVarManager() void ConVarManager::OnSourceModAllInitialized() { - /* Only valid with ServerGameDLL006 or greater */ + /** + * Episode 2 has this function by default, but the older versions do not. + */ +#if !defined ORANGEBOX_BUILD if (g_SMAPI->GetGameDLLVersion() >= 6) +#endif { SH_ADD_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false); - m_CanQueryConVars = true; + m_bIsDLLQueryHooked = true; } HandleAccess sec; @@ -97,10 +101,15 @@ void ConVarManager::OnSourceModAllInitialized() void ConVarManager::OnSourceModShutdown() { - if (m_CanQueryConVars) + if (m_bIsDLLQueryHooked) { SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false); - SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, m_VSPIface, this, &ConVarManager::OnQueryCvarValueFinished, false); + m_bIsDLLQueryHooked = false; + } + else if (m_bIsVSPQueryHooked) + { + SH_REMOVE_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false); + m_bIsVSPQueryHooked = false; } IChangeableForward *fwd; @@ -125,27 +134,35 @@ void ConVarManager::OnSourceModShutdown() g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent); } -void ConVarManager::OnSourceModVSPReceived(IServerPluginCallbacks *iface) +/** + * Orange Box will never use this. + */ +void ConVarManager::OnSourceModVSPReceived() { - /* This will be called after OnSourceModAllInitialized(), so... - * - * If we haven't been able to hook the IServerGameDLL version at this point, - * then use hook IServerPluginCallbacks version from the engine. + /** + * Don't bother if the DLL is already hooked. */ - - /* The Ship currently only supports ServerPluginCallbacks001, but we need 002 */ - if (g_IsOriginalEngine) + if (m_bIsDLLQueryHooked) { return; } - if (!m_CanQueryConVars) + /* For later MM:S versions, use the updated API, since it's cleaner. */ +#if defined METAMOD_PLAPI_VERSION + int engine = g_SMAPI->GetSourceEngineBuild(); + if (engine == SOURCE_ENGINE_ORIGINAL || vsp_version < 2) { - m_VSPIface = iface; - - SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, iface, this, &ConVarManager::OnQueryCvarValueFinished, false); - m_CanQueryConVars = true; + return; } +#else + if (g_HL2.IsOriginalEngine() || vsp_version < 2) + { + return; + } +#endif + + SH_ADD_HOOK_MEMFUNC(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, this, &ConVarManager::OnQueryCvarValueFinished, false); + m_bIsVSPQueryHooked = true; } #if PLAPI_VERSION >= 12 @@ -306,7 +323,9 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo)) { return pInfo->handle; - } else { + } + else + { /* If we don't, then create a new handle from the convar */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); @@ -478,12 +497,18 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char QueryCvarCookie_t cookie; /* Call StartQueryCvarValue() in either the IVEngineServer or IServerPluginHelpers depending on situation */ - if (!m_VSPIface) + if (m_bIsDLLQueryHooked) { cookie = engine->StartQueryCvarValue(pPlayer, name); - } else { + } + else if (m_bIsVSPQueryHooked) + { cookie = serverpluginhelpers->StartQueryCvarValue(pPlayer, name); } + else + { + return InvalidQueryCvarCookie; + } ConVarQuery query = {cookie, pCallback, hndl}; m_ConVarQueries.push_back(query); @@ -505,7 +530,9 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar { pConVarList = new ConVarList(); plugin->SetProperty("ConVarList", pConVarList); - } else if (pConVarList->find(pConVar) != pConVarList->end()) { + } + else if (pConVarList->find(pConVar) != pConVarList->end()) + { /* If convar is already in list, then don't add it */ return; } @@ -568,6 +595,11 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) pForward->Execute(NULL); } +bool ConVarManager::IsQueryingSupported() +{ + return (m_bIsDLLQueryHooked || m_bIsVSPQueryHooked); +} + void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue) { IPluginFunction *pCallback = NULL; @@ -597,7 +629,9 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t * if (result == eQueryCvarValueStatus_ValueIntact) { pCallback->PushString(cvarValue); - } else { + } + else + { pCallback->PushString("\0"); } diff --git a/core/ConVarManager.h b/core/ConVarManager.h index 98d92c7f..61cb360a 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -80,7 +80,7 @@ public: public: // SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModShutdown(); - void OnSourceModVSPReceived(IServerPluginCallbacks *iface); + void OnSourceModVSPReceived(); public: // IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object); public: // IPluginsListener @@ -131,6 +131,8 @@ public: QueryCvarCookie_t QueryClientConVar(edict_t *pPlayer, const char *name, IPluginFunction *pCallback, Handle_t hndl); + bool IsQueryingSupported(); + #if PLAPI_VERSION >= 12 /** * Called when Metamod:Source is about to remove convar @@ -167,8 +169,8 @@ private: List m_ConVars; List m_ConVarQueries; Trie *m_ConVarCache; - IServerPluginCallbacks *m_VSPIface; - bool m_CanQueryConVars; + bool m_bIsDLLQueryHooked; + bool m_bIsVSPQueryHooked; #if PLAPI_VERSION < 12 bool m_IgnoreHandle; #endif diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 0a8ac2cb..993a0e98 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -38,7 +38,6 @@ #include CHalfLife2 g_HL2; -bool g_IsOriginalEngine = false; ConVar *sv_lan = NULL; namespace SourceHook @@ -90,15 +89,21 @@ CHalfLife2::~CHalfLife2() } CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; +bool is_original_engine = false; void CHalfLife2::OnSourceModStartup(bool late) { /* The Ship currently is the only known game to use an older version of the engine */ +#if defined METAMOD_PLAPI_VERSION + if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL) +#else if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0) +#endif + { + is_original_engine = true; + } + else if (g_pSharedChangeInfo == NULL) { - /* :TODO: Better engine versioning - perhaps something added to SourceMM? */ - g_IsOriginalEngine = true; - } else if (!g_pSharedChangeInfo) { g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); } } @@ -111,6 +116,13 @@ void CHalfLife2::OnSourceModAllInitialized() g_ShareSys.AddInterface(NULL, this); } +#if !defined METAMOD_PLAPI_VERSION +bool CHalfLife2::IsOriginalEngine() +{ + return is_original_engine; +} +#endif + IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() { return engine->GetChangeAccessor( (const edict_t *)this ); @@ -254,7 +266,7 @@ typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) { - if (!g_IsOriginalEngine) + if (g_pSharedChangeInfo != NULL) { if (offset) { @@ -262,7 +274,9 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) } else { pEdict->StateChanged(); } - } else { + } + else + { pEdict->m_fStateFlags |= FL_EDICT_CHANGED; } } diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 221e010a..ca5fb754 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -105,6 +105,9 @@ public: void PopCommandStack(); const CCommand *PeekCommandStack(); const char *CurrentCommandName(); +#if !defined METAMOD_PLAPI_VERSION + bool IsOriginalEngine(); +#endif private: DataTableInfo *_FindServerClass(const char *classname); private: @@ -120,6 +123,5 @@ private: }; extern CHalfLife2 g_HL2; -extern bool g_IsOriginalEngine; #endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 0c083ba3..3f63ef4b 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -799,6 +799,10 @@ RelativePath="..\ChatTriggers.h" > + + diff --git a/core/sm_globals.h b/core/sm_globals.h index ad1a3d38..b761fabf 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -143,7 +143,7 @@ public: /** * @brief Called when SourceMod receives a pointer to IServerPluginCallbacks from SourceMM */ - virtual void OnSourceModVSPReceived(IServerPluginCallbacks *iface) + virtual void OnSourceModVSPReceived() { } diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 95b2d580..b18d376c 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -507,7 +507,7 @@ static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *param char *name; IPluginFunction *pCallback; - if (g_IsOriginalEngine) + if (!g_ConVarManager.IsQueryingSupported()) { if (!s_QueryAlreadyWarned) { diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 6a8e87ca..d3930bb8 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -36,17 +36,6 @@ #include "PlayerManager.h" #include "HalfLife2.h" -IServerPluginCallbacks *g_VSP = NULL; - -class HalfLifeNatives : public SMGlobalClass -{ -public: //SMGlobalClass - void OnSourceModVSPReceived(IServerPluginCallbacks *iface) - { - g_VSP = iface; - } -}; - static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params) { engrandom->SetSeed(params[1]); @@ -270,7 +259,10 @@ static cell_t smn_CreateDialog(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); } - serverpluginhelpers->CreateMessage(pPlayer->GetEdict(), static_cast(params[3]), pKV, g_VSP); + serverpluginhelpers->CreateMessage(pPlayer->GetEdict(), + static_cast(params[3]), + pKV, + vsp_interface); return 1; } @@ -415,8 +407,6 @@ static cell_t ShowVGUIPanel(IPluginContext *pContext, const cell_t *params) return 1; } -static HalfLifeNatives s_HalfLifeNatives; - REGISTER_NATIVES(halflifeNatives) { {"CreateFakeClient", CreateFakeClient}, diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 4d4005d8..c9504b44 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -50,6 +50,8 @@ IPlayerInfoManager *playerinfo = NULL; IBaseFileSystem *basefilesystem = NULL; IEngineSound *enginesound = NULL; IServerPluginHelpers *serverpluginhelpers = NULL; +IServerPluginCallbacks *vsp_interface = NULL; +int vsp_version = 0; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -82,7 +84,13 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen gpGlobals = ismm->GetCGlobals(); ismm->AddListener(this, this); - ismm->EnableVSPListener(); + +#if defined METAMOD_PLAPI_VERSION + if ((vsp_interface = g_SMAPI->GetVSPInfo(&vsp_version)) == NULL) +#endif + { + g_SMAPI->EnableVSPListener(); + } return g_SourceMod.InitializeSourceMod(error, maxlen, late); } @@ -153,15 +161,44 @@ void SourceMod_Core::OnVSPListening(IServerPluginCallbacks *iface) /* This shouldn't happen */ if (!iface) { - g_Logger.LogFatal("Metamod:Source version is out of date. SourceMod requires 1.4 or greater."); + g_Logger.LogFatal("Metamod:Source version is out of date. SourceMod requires 1.4.2 or greater."); return; } + if (vsp_interface == NULL) + { + vsp_interface = iface; + } + + if (!g_Loaded) + { + return; + } + +#if defined METAMOD_PLAPI_VERSION + if (vsp_version == 0) + { + g_SMAPI->GetVSPInfo(&vsp_version); + } +#else + if (vsp_version == 0) + { + if (strcmp(g_SourceMod.GetGameFolderName(), "ship") == 0) + { + vsp_version = 1; + } + else + { + vsp_version = 2; + } + } +#endif + /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) { - pBase->OnSourceModVSPReceived(iface); + pBase->OnSourceModVSPReceived(); pBase = pBase->m_pGlobalClassNext; } } diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 472fc398..0b27fe88 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -96,6 +96,8 @@ extern IPlayerInfoManager *playerinfo; extern IBaseFileSystem *basefilesystem; extern IEngineSound *enginesound; extern IServerPluginHelpers *serverpluginhelpers; +extern IServerPluginCallbacks *vsp_interface; +extern int vsp_version; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index b094dc7d..777e98fe 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -306,6 +306,12 @@ void SourceModBase::StartSourceMod(bool late) /* We're loaded! */ g_Loaded = true; + + /* Initialize VSP stuff */ + if (vsp_interface != NULL) + { + g_SourceMod_Core.OnVSPListening(vsp_interface); + } } static bool g_LevelEndBarrier = false; diff --git a/core/sourcemod.h b/core/sourcemod.h index 378fff1f..d3be8dd4 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -128,6 +128,7 @@ private: bool m_GotBasePath; }; +extern bool g_Loaded; extern SourceModBase g_SourceMod; extern HandleType_t g_WrBitBufType; //:TODO: find a better place for this extern HandleType_t g_RdBitBufType; //:TODO: find a better place for this