extensions/sdktools/extension.cpp
author David Anderson <dvander@alliedmods.net>
Tue May 20 02:24:42 2008 +0000 (2008-05-20)
changeset 2060 9f794b82bb7e
parent 2044 46a8839bd87a
child 2108 cb79854cf137
permissions -rw-r--r--
fixed a delayed unload crash in sdktools
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "extension.h"
    33 #include "vcallbuilder.h"
    34 #include "vnatives.h"
    35 #include "vhelpers.h"
    36 #include "vglobals.h"
    37 #include "tempents.h"
    38 #include "vsound.h"
    39 #include "output.h"
    40 
    41 #if defined ORANGEBOX_BUILD
    42 	#define SDKTOOLS_GAME_FILE		"sdktools.games.ep2"
    43 #else
    44 	#define SDKTOOLS_GAME_FILE		"sdktools.games"
    45 #endif
    46 
    47 /**
    48  * @file extension.cpp
    49  * @brief Implements SDK Tools extension code.
    50  */
    51 
    52 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
    53 
    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;
    66 ICvar *icvar = NULL;
    67 IServer *iserver = NULL;
    68 SourceHook::CallClass<IVEngineServer> *enginePatch = NULL;
    69 SourceHook::CallClass<IEngineSound> *enginesoundPatch = NULL;
    70 HandleType_t g_CallHandle = 0;
    71 HandleType_t g_TraceHandle = 0;
    72 
    73 SMEXT_LINK(&g_SdkTools);
    74 
    75 extern sp_nativeinfo_t g_CallNatives[];
    76 extern sp_nativeinfo_t g_TENatives[];
    77 extern sp_nativeinfo_t g_TRNatives[];
    78 extern sp_nativeinfo_t g_StringTableNatives[];
    79 extern sp_nativeinfo_t g_VoiceNatives[];
    80 extern sp_nativeinfo_t g_EntInputNatives[];
    81 extern sp_nativeinfo_t g_TeamNatives[];
    82 
    83 bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
    84 {
    85 	sharesys->AddDependency(myself, "bintools.ext", true, true);
    86 	sharesys->AddNatives(myself, g_CallNatives);
    87 	sharesys->AddNatives(myself, g_Natives);
    88 	sharesys->AddNatives(myself, g_TENatives);
    89 	sharesys->AddNatives(myself, g_SoundNatives);
    90 	sharesys->AddNatives(myself, g_TRNatives);
    91 	sharesys->AddNatives(myself, g_StringTableNatives);
    92 	sharesys->AddNatives(myself, g_VoiceNatives);
    93 	sharesys->AddNatives(myself, g_EntInputNatives);
    94 	sharesys->AddNatives(myself, g_TeamNatives);
    95 	sharesys->AddNatives(myself, g_EntOutputNatives);
    96 
    97 	SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers);
    98 
    99 	if (!gameconfs->LoadGameConfigFile(SDKTOOLS_GAME_FILE, &g_pGameConf, error, maxlength))
   100 	{
   101 		return false;
   102 	}
   103 
   104 	playerhelpers->AddClientListener(&g_SdkTools);
   105 	g_CallHandle = handlesys->CreateType("ValveCall", this, 0, NULL, NULL, myself->GetIdentity(), NULL);
   106 	g_TraceHandle = handlesys->CreateType("TraceRay", this, 0, NULL, NULL, myself->GetIdentity(), NULL);
   107 
   108 #if defined ORANGEBOX_BUILD
   109 	g_pCVar = icvar;
   110 #endif
   111 	CONVAR_REGISTER(this);
   112 
   113 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true);
   114 
   115 	playerhelpers->RegisterCommandTargetProcessor(this);
   116 
   117 	MathLib_Init(2.2f, 2.2f, 0.0f, 2);
   118 
   119 	spengine = g_pSM->GetScriptingEngine();
   120 
   121 	plsys->AddPluginsListener(&g_OutputManager);
   122 
   123 	g_OutputManager.Init();
   124 
   125 	VoiceInit();
   126 
   127 	return true;
   128 }
   129 
   130 void SDKTools::OnHandleDestroy(HandleType_t type, void *object)
   131 {
   132 	if (type == g_CallHandle)
   133 	{
   134 		ValveCall *v = (ValveCall *)object;
   135 		delete v;
   136 	}
   137 	else if (type == g_TraceHandle)
   138 	{
   139 		trace_t *tr = (trace_t *)object;
   140 		delete tr;
   141 	}
   142 }
   143 
   144 void SDKTools::SDK_OnUnload()
   145 {
   146 	SourceHook::List<ValveCall *>::iterator iter;
   147 	for (iter = g_RegCalls.begin();
   148 		 iter != g_RegCalls.end();
   149 		 iter++)
   150 	{
   151 		delete (*iter);
   152 	}
   153 	g_RegCalls.clear();
   154 	ShutdownHelpers();
   155 
   156 	if (g_pAcceptInput)
   157 	{
   158 		g_pAcceptInput->Destroy();
   159 		g_pAcceptInput = NULL;
   160 	}
   161 
   162 	g_TEManager.Shutdown();
   163 	s_TempEntHooks.Shutdown();
   164 	s_SoundHooks.Shutdown();
   165 
   166 	gameconfs->CloseGameConfigFile(g_pGameConf);
   167 	playerhelpers->RemoveClientListener(&g_SdkTools);
   168 	playerhelpers->UnregisterCommandTargetProcessor(this);
   169 	plsys->RemovePluginsListener(&g_OutputManager);
   170 
   171 	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true);
   172 
   173 	if (enginePatch)
   174 	{
   175 		SH_RELEASE_CALLCLASS(enginePatch);
   176 		enginePatch = NULL;
   177 	}
   178 	if (enginesoundPatch)
   179 	{
   180 		SH_RELEASE_CALLCLASS(enginesoundPatch);
   181 		enginesoundPatch = NULL;
   182 	}
   183 }
   184 
   185 bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
   186 {
   187 	GET_V_IFACE_ANY(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
   188 	GET_V_IFACE_ANY(GetEngineFactory, engsound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION);
   189 	GET_V_IFACE_ANY(GetEngineFactory, enginetrace, IEngineTrace, INTERFACEVERSION_ENGINETRACE_SERVER);
   190 	GET_V_IFACE_ANY(GetEngineFactory, netstringtables, INetworkStringTableContainer, INTERFACENAME_NETWORKSTRINGTABLESERVER);
   191 	GET_V_IFACE_ANY(GetEngineFactory, pluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS);
   192 	GET_V_IFACE_ANY(GetServerFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
   193 	GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER);
   194 	GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER);
   195 	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
   196 
   197 	enginePatch = SH_GET_CALLCLASS(engine);
   198 	enginesoundPatch = SH_GET_CALLCLASS(engsound);
   199 
   200 	return true;
   201 }
   202 
   203 void SDKTools::SDK_OnAllLoaded()
   204 {
   205 	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
   206 
   207 	if (!g_pBinTools)
   208 	{
   209 		return;
   210 	}
   211 
   212 	g_TEManager.Initialize();
   213 	s_TempEntHooks.Initialize();
   214 	s_SoundHooks.Initialize();
   215 	InitializeValveGlobals();
   216 	GetIServer();
   217 }
   218 
   219 bool SDKTools::QueryRunning(char *error, size_t maxlength)
   220 {
   221 	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
   222 
   223 	return true;
   224 }
   225 
   226 bool SDKTools::QueryInterfaceDrop(SMInterface *pInterface)
   227 {
   228 	if (pInterface == g_pBinTools)
   229 	{
   230 		return false;
   231 	}
   232 
   233 	return IExtensionInterface::QueryInterfaceDrop(pInterface);
   234 }
   235 
   236 void SDKTools::NotifyInterfaceDrop(SMInterface *pInterface)
   237 {
   238 	SourceHook::List<ValveCall *>::iterator iter;
   239 	for (iter = g_RegCalls.begin();
   240 		iter != g_RegCalls.end();
   241 		iter++)
   242 	{
   243 		delete (*iter);
   244 	}
   245 	g_RegCalls.clear();
   246 	ShutdownHelpers();
   247 
   248 	g_TEManager.Shutdown();
   249 	s_TempEntHooks.Shutdown();
   250 
   251 	if (g_pAcceptInput)
   252 	{
   253 		g_pAcceptInput->Destroy();
   254 		g_pAcceptInput = NULL;
   255 	}
   256 }
   257 
   258 bool SDKTools::RegisterConCommandBase(ConCommandBase *pVar)
   259 {
   260 #if defined METAMOD_PLAPI_VERSION
   261 	return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar);
   262 #else
   263 	return g_SMAPI->RegisterConCmdBase(g_PLAPI, pVar);
   264 #endif
   265 }
   266 
   267 bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
   268 {
   269 	const char *name;
   270 	char key[32];
   271 	int count, n = 1;
   272 
   273 	if (!(name=g_pGameConf->GetKeyValue("SlapSoundCount")))
   274 	{
   275 		RETURN_META_VALUE(MRES_IGNORED, true);
   276 	}
   277 
   278 	count = atoi(name);
   279 
   280 	while (n <= count)
   281 	{
   282 		snprintf(key, sizeof(key), "SlapSound%d", n);
   283 		if ((name=g_pGameConf->GetKeyValue(key)))
   284 		{
   285 			engsound->PrecacheSound(name, true);
   286 		}
   287 		n++;
   288 	}
   289 
   290 	RETURN_META_VALUE(MRES_IGNORED, true);
   291 }
   292 
   293 bool SDKTools::ProcessCommandTarget(cmd_target_info_t *info)
   294 {
   295 	if (strcmp(info->pattern, "@aim") != 0)
   296 	{
   297 		return false;
   298 	}
   299 
   300 	IGamePlayer *pAdmin = info->admin ? playerhelpers->GetGamePlayer(info->admin) : NULL;
   301 
   302 	/* The server can't aim, of course. */
   303 	if (pAdmin == NULL)
   304 	{
   305 		return false;
   306 	}
   307 
   308 	int player_index;
   309 	if ((player_index = GetClientAimTarget(pAdmin->GetEdict(), true)) < 1)
   310 	{
   311 		info->reason = COMMAND_TARGET_NONE;
   312 		info->num_targets = 0;
   313 		return true;
   314 	}
   315 
   316 	IGamePlayer *pTarget = playerhelpers->GetGamePlayer(player_index);
   317 
   318 	if (pTarget == NULL)
   319 	{
   320 		info->reason = COMMAND_TARGET_NONE;
   321 		info->num_targets = 0;
   322 		return true;
   323 	}
   324 
   325 	info->reason = playerhelpers->FilterCommandTarget(pAdmin, pTarget, info->flags);
   326 	if (info->reason != COMMAND_TARGET_VALID)
   327 	{
   328 		info->num_targets = 0;
   329 		return true;
   330 	}
   331 
   332 	info->targets[0] = player_index;
   333 	info->num_targets = 1;
   334 	info->reason = COMMAND_TARGET_VALID;
   335 	info->target_name_style = COMMAND_TARGETNAME_RAW;
   336 	snprintf(info->target_name, info->target_name_maxlength, "%s", pTarget->GetName());
   337 
   338 	return true;
   339 }