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