Fix SDKHooks load issue and reliance on gEntList ptr on CS:GO and Dota 2 on Windows.
3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include <sourcemod_version.h>
33 #include "extension.h"
34 #include <compat_wrappers.h>
35 #include "vcallbuilder.h"
43 #include "gamerulesnatives.h"
44 #include <ISDKTools.h>
45 #include "clientnatives.h"
46 #include "teamnatives.h"
49 * @brief Implements SDK Tools extension code.
52 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
54 SDKTools g_SdkTools; /**< Global singleton for extension's main interface */
55 IServerGameEnts *gameents = NULL;
56 IEngineTrace *enginetrace = NULL;
57 IEngineSound *engsound = NULL;
58 INetworkStringTableContainer *netstringtables = NULL;
59 IServerPluginHelpers *pluginhelpers = NULL;
60 IBinTools *g_pBinTools = NULL;
61 IGameConfig *g_pGameConf = NULL;
62 IGameHelpers *g_pGameHelpers = NULL;
63 IServerGameClients *serverClients = NULL;
64 IVoiceServer *voiceserver = NULL;
65 IPlayerInfoManager *playerinfomngr = NULL;
67 IServer *iserver = NULL;
68 CGlobalVars *gpGlobals;
70 #if SOURCE_ENGINE >= SE_ORANGEBOX
71 IServerTools *servertools = NULL;
74 SourceHook::CallClass<IVEngineServer> *enginePatch = NULL;
75 SourceHook::CallClass<IEngineSound> *enginesoundPatch = NULL;
76 HandleType_t g_CallHandle = 0;
77 HandleType_t g_TraceHandle = 0;
78 ISDKTools *g_pSDKTools;
80 SMEXT_LINK(&g_SdkTools);
82 extern sp_nativeinfo_t g_CallNatives[];
83 extern sp_nativeinfo_t g_TENatives[];
84 extern sp_nativeinfo_t g_TRNatives[];
85 extern sp_nativeinfo_t g_StringTableNatives[];
86 extern sp_nativeinfo_t g_VoiceNatives[];
87 extern sp_nativeinfo_t g_EntInputNatives[];
88 extern sp_nativeinfo_t g_TeamNatives[];
89 extern sp_nativeinfo_t g_GameRulesNatives[];
90 extern sp_nativeinfo_t g_ClientNatives[];
92 static void InitSDKToolsAPI();
94 bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
98 if (!gameconfs->LoadGameConfigFile("sdktools.games", &g_pGameConf, error, maxlength))
103 sharesys->AddDependency(myself, "bintools.ext", true, true);
104 sharesys->AddNatives(myself, g_CallNatives);
105 sharesys->AddNatives(myself, g_Natives);
106 sharesys->AddNatives(myself, g_TENatives);
107 sharesys->AddNatives(myself, g_SoundNatives);
108 sharesys->AddNatives(myself, g_TRNatives);
109 sharesys->AddNatives(myself, g_StringTableNatives);
110 sharesys->AddNatives(myself, g_VoiceNatives);
111 sharesys->AddNatives(myself, g_EntInputNatives);
112 sharesys->AddNatives(myself, g_TeamNatives);
113 sharesys->AddNatives(myself, g_EntOutputNatives);
114 sharesys->AddNatives(myself, g_GameRulesNatives);
115 sharesys->AddNatives(myself, g_ClientNatives);
117 SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers);
119 playerhelpers->AddClientListener(&g_SdkTools);
120 g_CallHandle = handlesys->CreateType("ValveCall", this, 0, NULL, NULL, myself->GetIdentity(), &err);
121 if (g_CallHandle == 0)
123 snprintf(error, maxlength, "Could not create call handle type (err: %d)", err);
127 TypeAccess TraceAccess;
128 handlesys->InitAccessDefaults(&TraceAccess, NULL);
129 TraceAccess.ident = myself->GetIdentity();
130 TraceAccess.access[HTypeAccess_Create] = true;
131 TraceAccess.access[HTypeAccess_Inherit] = true;
132 g_TraceHandle = handlesys->CreateType("TraceRay", this, 0, &TraceAccess, NULL, myself->GetIdentity(), &err);
133 if (g_TraceHandle == 0)
135 handlesys->RemoveType(g_CallHandle, myself->GetIdentity());
137 snprintf(error, maxlength, "Could not create traceray handle type (err: %d)", err);
141 #if SOURCE_ENGINE >= SE_ORANGEBOX
144 CONVAR_REGISTER(this);
146 SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SDKTools::LevelInit), true);
148 playerhelpers->RegisterCommandTargetProcessor(this);
150 MathLib_Init(2.2f, 2.2f, 0.0f, 2);
152 spengine = g_pSM->GetScriptingEngine();
154 plsys->AddPluginsListener(&g_OutputManager);
156 CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
157 g_OutputManager.Init();
163 GameRulesNativesInit();
170 void SDKTools::OnHandleDestroy(HandleType_t type, void *object)
172 if (type == g_CallHandle)
174 ValveCall *v = (ValveCall *)object;
177 else if (type == g_TraceHandle)
179 trace_t *tr = (trace_t *)object;
184 void SDKTools::SDK_OnUnload()
186 SourceHook::List<ValveCall *>::iterator iter;
187 for (iter = g_RegCalls.begin();
188 iter != g_RegCalls.end();
198 g_pAcceptInput->Destroy();
199 g_pAcceptInput = NULL;
202 g_TEManager.Shutdown();
203 s_TempEntHooks.Shutdown();
204 s_SoundHooks.Shutdown();
206 g_OutputManager.Shutdown();
208 gameconfs->CloseGameConfigFile(g_pGameConf);
209 playerhelpers->RemoveClientListener(&g_SdkTools);
210 playerhelpers->UnregisterCommandTargetProcessor(this);
211 plsys->RemovePluginsListener(&g_OutputManager);
213 SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SDKTools::LevelInit), true);
217 SH_RELEASE_CALLCLASS(enginePatch);
220 if (enginesoundPatch)
222 SH_RELEASE_CALLCLASS(enginesoundPatch);
223 enginesoundPatch = NULL;
227 if (g_CallHandle != 0)
229 if ((err = handlesys->RemoveType(g_CallHandle, myself->GetIdentity())) != true)
231 g_pSM->LogError(myself, "Could not remove call handle (type=%x, err=%d)", g_CallHandle, err);
235 if (g_TraceHandle != 0)
237 if ((err = handlesys->RemoveType(g_TraceHandle, myself->GetIdentity())) != true)
239 g_pSM->LogError(myself, "Could not remove trace handle (type=%x, err=%d)", g_TraceHandle, err);
244 bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
246 GET_V_IFACE_ANY(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
247 GET_V_IFACE_ANY(GetEngineFactory, engsound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION);
248 GET_V_IFACE_ANY(GetEngineFactory, enginetrace, IEngineTrace, INTERFACEVERSION_ENGINETRACE_SERVER);
249 GET_V_IFACE_ANY(GetEngineFactory, netstringtables, INetworkStringTableContainer, INTERFACENAME_NETWORKSTRINGTABLESERVER);
250 #if SOURCE_ENGINE != SE_DOTA
251 GET_V_IFACE_ANY(GetEngineFactory, pluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS);
253 GET_V_IFACE_ANY(GetServerFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
254 GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER);
255 GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER);
256 GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
258 #if SOURCE_ENGINE >= SE_ORANGEBOX
259 GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
262 gpGlobals = ismm->GetCGlobals();
263 enginePatch = SH_GET_CALLCLASS(engine);
264 enginesoundPatch = SH_GET_CALLCLASS(engsound);
269 void SDKTools::SDK_OnAllLoaded()
271 SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
278 g_TEManager.Initialize();
279 s_TempEntHooks.Initialize();
280 s_SoundHooks.Initialize();
281 g_Hooks.Initialize();
282 InitializeValveGlobals();
285 void SDKTools::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
291 bool SDKTools::QueryRunning(char *error, size_t maxlength)
293 SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
298 bool SDKTools::QueryInterfaceDrop(SMInterface *pInterface)
300 if (pInterface == g_pBinTools)
305 return IExtensionInterface::QueryInterfaceDrop(pInterface);
308 void SDKTools::NotifyInterfaceDrop(SMInterface *pInterface)
310 SourceHook::List<ValveCall *>::iterator iter;
311 for (iter = g_RegCalls.begin();
312 iter != g_RegCalls.end();
320 g_TEManager.Shutdown();
321 s_TempEntHooks.Shutdown();
325 g_pAcceptInput->Destroy();
326 g_pAcceptInput = NULL;
330 bool SDKTools::RegisterConCommandBase(ConCommandBase *pVar)
332 #if defined METAMOD_PLAPI_VERSION
333 return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar);
335 return g_SMAPI->RegisterConCmdBase(g_PLAPI, pVar);
339 bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
345 if (!(name=g_pGameConf->GetKeyValue("SlapSoundCount")))
347 RETURN_META_VALUE(MRES_IGNORED, true);
354 snprintf(key, sizeof(key), "SlapSound%d", n);
355 if ((name=g_pGameConf->GetKeyValue(key)))
357 engsound->PrecacheSound(name, true);
362 RETURN_META_VALUE(MRES_IGNORED, true);
365 bool SDKTools::ProcessCommandTarget(cmd_target_info_t *info)
367 IGamePlayer *pAdmin = info->admin ? playerhelpers->GetGamePlayer(info->admin) : NULL;
369 if (strcmp(info->pattern, "@aim") == 0)
371 /* The server can't aim, of course. */
378 if ((player_index = GetClientAimTarget(pAdmin->GetEdict(), true)) < 1)
380 info->reason = COMMAND_TARGET_NONE;
381 info->num_targets = 0;
385 IGamePlayer *pTarget = playerhelpers->GetGamePlayer(player_index);
389 info->reason = COMMAND_TARGET_NONE;
390 info->num_targets = 0;
394 info->reason = playerhelpers->FilterCommandTarget(pAdmin, pTarget, info->flags);
395 if (info->reason != COMMAND_TARGET_VALID)
397 info->num_targets = 0;
401 info->targets[0] = player_index;
402 info->num_targets = 1;
403 info->reason = COMMAND_TARGET_VALID;
404 info->target_name_style = COMMAND_TARGETNAME_RAW;
405 snprintf(info->target_name, info->target_name_maxlength, "%s", pTarget->GetName());
408 else if (strcmp(info->pattern, "@spec") == 0)
410 const char *teamname = tools_GetTeamName(1);
411 if (strcasecmp(teamname, "spectator") != 0)
413 info->num_targets = 0;
414 for (int i = 1; i <= playerhelpers->GetMaxClients(); i++)
416 IGamePlayer *player = playerhelpers->GetGamePlayer(i);
417 if (player == NULL || !player->IsInGame())
419 IPlayerInfo *plinfo = player->GetPlayerInfo();
422 if (plinfo->GetTeamIndex() == 1 &&
423 playerhelpers->FilterCommandTarget(pAdmin, player, info->flags) ==
424 COMMAND_TARGET_VALID)
426 info->targets[info->num_targets++] = i;
429 info->reason = info->num_targets > 0 ? COMMAND_TARGET_VALID : COMMAND_TARGET_EMPTY_FILTER;
430 info->target_name_style = COMMAND_TARGETNAME_ML;
431 snprintf(info->target_name, info->target_name_maxlength, "all spectators");
438 const char *SDKTools::GetExtensionVerString()
440 return SOURCEMOD_VERSION;
443 const char *SDKTools::GetExtensionDateString()
445 return SOURCEMOD_BUILD_TIME;
448 void SDKTools::OnClientPutInServer(int client)
450 g_Hooks.OnClientPutInServer(client);
453 class SDKTools_API : public ISDKTools
456 virtual const char *GetInterfaceName()
458 return SMINTERFACE_SDKTOOLS_NAME;
461 virtual unsigned int GetInterfaceVersion()
463 return SMINTERFACE_SDKTOOLS_VERSION;
466 virtual IServer *GetIServer()
471 virtual void *GetGameRules()
476 return *g_pGameRules;
480 static void InitSDKToolsAPI()
482 g_pSDKTools = &g_SDKTools_API;
483 sharesys->AddInterface(myself, g_pSDKTools);