extensions/sdktools/extension.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Thu Jul 04 11:28:32 2013 -0400 (2013-07-04)
changeset 3931 576fa42454dc
parent 3854 8abb0924497b
child 4188 89782d5fc91b
permissions -rw-r--r--
Fixed build for real.
ds@783
     1
/**
ds@783
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1233
     4
 * SourceMod SDKTools Extension
fyrenmoo@3089
     5
 * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
ds@783
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1233
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1233
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1233
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
ds@783
    28
 *
ds@783
    29
 * Version: $Id$
ds@783
    30
 */
ds@783
    31
dvander@2783
    32
#include <sourcemod_version.h>
ds@783
    33
#include "extension.h"
ds@2400
    34
#include <compat_wrappers.h>
dvander@950
    35
#include "vcallbuilder.h"
dvander@954
    36
#include "vnatives.h"
dvander@1169
    37
#include "vhelpers.h"
ds@1240
    38
#include "vglobals.h"
faluco@1031
    39
#include "tempents.h"
faluco@1735
    40
#include "vsound.h"
pred@1958
    41
#include "output.h"
pred@2711
    42
#include "hooks.h"
skamonkey@3333
    43
#include "gamerulesnatives.h"
dvander@2503
    44
#include <ISDKTools.h>
bluebriansimon@3339
    45
#include "clientnatives.h"
skamonkey@3816
    46
#include "teamnatives.h"
ds@783
    47
/**
ds@783
    48
 * @file extension.cpp
ds@995
    49
 * @brief Implements SDK Tools extension code.
ds@783
    50
 */
ds@783
    51
faluco@1262
    52
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
faluco@1262
    53
ds@783
    54
SDKTools g_SdkTools;		/**< Global singleton for extension's main interface */
ds@783
    55
IServerGameEnts *gameents = NULL;
faluco@1075
    56
IEngineTrace *enginetrace = NULL;
ds@1114
    57
IEngineSound *engsound = NULL;
ds@1114
    58
INetworkStringTableContainer *netstringtables = NULL;
dvander@1169
    59
IServerPluginHelpers *pluginhelpers = NULL;
ds@783
    60
IBinTools *g_pBinTools = NULL;
dvander@950
    61
IGameConfig *g_pGameConf = NULL;
faluco@1031
    62
IGameHelpers *g_pGameHelpers = NULL;
faluco@1219
    63
IServerGameClients *serverClients = NULL;
ds@1240
    64
IVoiceServer *voiceserver = NULL;
teame06@1239
    65
IPlayerInfoManager *playerinfomngr = NULL;
faluco@1560
    66
ICvar *icvar = NULL;
faluco@1769
    67
IServer *iserver = NULL;
ds@2400
    68
CGlobalVars *gpGlobals;
skamonkey@3280
    69
skamonkey@3280
    70
#if SOURCE_ENGINE >= SE_ORANGEBOX
skamonkey@3280
    71
IServerTools *servertools = NULL;
skamonkey@3280
    72
#endif
skamonkey@3280
    73
faluco@1735
    74
SourceHook::CallClass<IVEngineServer> *enginePatch = NULL;
faluco@1735
    75
SourceHook::CallClass<IEngineSound> *enginesoundPatch = NULL;
dvander@950
    76
HandleType_t g_CallHandle = 0;
faluco@1075
    77
HandleType_t g_TraceHandle = 0;
dvander@2503
    78
ISDKTools *g_pSDKTools;
ds@783
    79
ds@783
    80
SMEXT_LINK(&g_SdkTools);
ds@783
    81
dvander@950
    82
extern sp_nativeinfo_t g_CallNatives[];
faluco@1031
    83
extern sp_nativeinfo_t g_TENatives[];
faluco@1075
    84
extern sp_nativeinfo_t g_TRNatives[];
ds@1114
    85
extern sp_nativeinfo_t g_StringTableNatives[];
teame06@1235
    86
extern sp_nativeinfo_t g_VoiceNatives[];
faluco@1498
    87
extern sp_nativeinfo_t g_EntInputNatives[];
faluco@1613
    88
extern sp_nativeinfo_t g_TeamNatives[];
skamonkey@3333
    89
extern sp_nativeinfo_t g_GameRulesNatives[];
bluebriansimon@3339
    90
extern sp_nativeinfo_t g_ClientNatives[];
dvander@950
    91
dvander@2503
    92
static void InitSDKToolsAPI();
dvander@2503
    93
ds@783
    94
bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
ds@783
    95
{
dvander@2306
    96
	HandleError err;
dvander@2306
    97
dvander@2529
    98
	if (!gameconfs->LoadGameConfigFile("sdktools.games", &g_pGameConf, error, maxlength))
pred@2124
    99
	{
pred@2124
   100
		return false;
pred@2124
   101
	}
pred@2124
   102
dvander@950
   103
	sharesys->AddDependency(myself, "bintools.ext", true, true);
dvander@950
   104
	sharesys->AddNatives(myself, g_CallNatives);
dvander@954
   105
	sharesys->AddNatives(myself, g_Natives);
faluco@1031
   106
	sharesys->AddNatives(myself, g_TENatives);
dvander@1047
   107
	sharesys->AddNatives(myself, g_SoundNatives);
faluco@1075
   108
	sharesys->AddNatives(myself, g_TRNatives);
ds@1114
   109
	sharesys->AddNatives(myself, g_StringTableNatives);
teame06@1235
   110
	sharesys->AddNatives(myself, g_VoiceNatives);
faluco@1498
   111
	sharesys->AddNatives(myself, g_EntInputNatives);
faluco@1613
   112
	sharesys->AddNatives(myself, g_TeamNatives);
pred@1958
   113
	sharesys->AddNatives(myself, g_EntOutputNatives);
skamonkey@3333
   114
	sharesys->AddNatives(myself, g_GameRulesNatives);
bluebriansimon@3339
   115
	sharesys->AddNatives(myself, g_ClientNatives);
faluco@1031
   116
faluco@1031
   117
	SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers);
ds@783
   118
teame06@1235
   119
	playerhelpers->AddClientListener(&g_SdkTools);
dvander@2306
   120
	g_CallHandle = handlesys->CreateType("ValveCall", this, 0, NULL, NULL, myself->GetIdentity(), &err);
dvander@2306
   121
	if (g_CallHandle == 0)
dvander@2306
   122
	{
dvander@2306
   123
		snprintf(error, maxlength, "Could not create call handle type (err: %d)", err);	
dvander@2306
   124
		return false;
dvander@2306
   125
	}
pred@2108
   126
pred@2108
   127
	TypeAccess TraceAccess;
pred@2108
   128
	handlesys->InitAccessDefaults(&TraceAccess, NULL);
pred@2116
   129
	TraceAccess.ident = myself->GetIdentity();
pred@2108
   130
	TraceAccess.access[HTypeAccess_Create] = true;
pred@2116
   131
	TraceAccess.access[HTypeAccess_Inherit] = true;
dvander@2306
   132
	g_TraceHandle = handlesys->CreateType("TraceRay", this, 0, &TraceAccess, NULL, myself->GetIdentity(), &err);
dvander@2306
   133
	if (g_TraceHandle == 0)
dvander@2306
   134
	{
dvander@2306
   135
		handlesys->RemoveType(g_CallHandle, myself->GetIdentity());
dvander@2306
   136
		g_CallHandle = 0;
dvander@2306
   137
		snprintf(error, maxlength, "Could not create traceray handle type (err: %d)", err);
dvander@2306
   138
		return false;
dvander@2306
   139
	}
ds@783
   140
ds@2400
   141
#if SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1560
   142
	g_pCVar = icvar;
faluco@1560
   143
#endif
faluco@1560
   144
	CONVAR_REGISTER(this);
dvander@1052
   145
kyle@3819
   146
	SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SDKTools::LevelInit), true);
faluco@1262
   147
dvander@1628
   148
	playerhelpers->RegisterCommandTargetProcessor(this);
dvander@1628
   149
dvander@1611
   150
	MathLib_Init(2.2f, 2.2f, 0.0f, 2);
dvander@1611
   151
pred@1958
   152
	spengine = g_pSM->GetScriptingEngine();
pred@1958
   153
pred@1958
   154
	plsys->AddPluginsListener(&g_OutputManager);
pred@1958
   155
fyrenmoo@3089
   156
	CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
pred@1958
   157
	g_OutputManager.Init();
pred@1958
   158
dvander@2044
   159
	VoiceInit();
dvander@2044
   160
dvander@2503
   161
	GetIServer();
dvander@2503
   162
skamonkey@3333
   163
	GameRulesNativesInit();
skamonkey@3333
   164
dvander@2503
   165
	InitSDKToolsAPI();
dvander@2503
   166
ds@783
   167
	return true;
ds@783
   168
}
ds@783
   169
dvander@950
   170
void SDKTools::OnHandleDestroy(HandleType_t type, void *object)
dvander@950
   171
{
dvander@950
   172
	if (type == g_CallHandle)
dvander@950
   173
	{
dvander@950
   174
		ValveCall *v = (ValveCall *)object;
dvander@950
   175
		delete v;
dvander@1628
   176
	}
dvander@1628
   177
	else if (type == g_TraceHandle)
dvander@1628
   178
	{
faluco@1075
   179
		trace_t *tr = (trace_t *)object;
faluco@1075
   180
		delete tr;
faluco@1075
   181
	}
dvander@950
   182
}
dvander@950
   183
dvander@950
   184
void SDKTools::SDK_OnUnload()
dvander@950
   185
{
faluco@1560
   186
	SourceHook::List<ValveCall *>::iterator iter;
dvander@954
   187
	for (iter = g_RegCalls.begin();
dvander@954
   188
		 iter != g_RegCalls.end();
dvander@954
   189
		 iter++)
dvander@954
   190
	{
dvander@954
   191
		delete (*iter);
dvander@954
   192
	}
dvander@954
   193
	g_RegCalls.clear();
dvander@1169
   194
	ShutdownHelpers();
dvander@954
   195
faluco@1498
   196
	if (g_pAcceptInput)
faluco@1498
   197
	{
faluco@1498
   198
		g_pAcceptInput->Destroy();
faluco@1498
   199
		g_pAcceptInput = NULL;
faluco@1498
   200
	}
faluco@1498
   201
faluco@1031
   202
	g_TEManager.Shutdown();
faluco@1255
   203
	s_TempEntHooks.Shutdown();
faluco@1735
   204
	s_SoundHooks.Shutdown();
pred@2711
   205
	g_Hooks.Shutdown();
dvander@3414
   206
	g_OutputManager.Shutdown();
faluco@1031
   207
dvander@950
   208
	gameconfs->CloseGameConfigFile(g_pGameConf);
teame06@1235
   209
	playerhelpers->RemoveClientListener(&g_SdkTools);
dvander@1628
   210
	playerhelpers->UnregisterCommandTargetProcessor(this);
dvander@2060
   211
	plsys->RemovePluginsListener(&g_OutputManager);
faluco@1262
   212
kyle@3819
   213
	SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SDKTools::LevelInit), true);
faluco@1735
   214
faluco@1735
   215
	if (enginePatch)
faluco@1735
   216
	{
faluco@1735
   217
		SH_RELEASE_CALLCLASS(enginePatch);
faluco@1735
   218
		enginePatch = NULL;
faluco@1735
   219
	}
faluco@1735
   220
	if (enginesoundPatch)
faluco@1735
   221
	{
faluco@1735
   222
		SH_RELEASE_CALLCLASS(enginesoundPatch);
faluco@1735
   223
		enginesoundPatch = NULL;
faluco@1735
   224
	}
dvander@2306
   225
dvander@2306
   226
	bool err;
dvander@2306
   227
	if (g_CallHandle != 0)
dvander@2306
   228
	{
dvander@2306
   229
		if ((err = handlesys->RemoveType(g_CallHandle, myself->GetIdentity())) != true)
dvander@2306
   230
		{
dvander@2306
   231
			g_pSM->LogError(myself, "Could not remove call handle (type=%x, err=%d)", g_CallHandle, err);
dvander@2306
   232
		}
dvander@2306
   233
	}
dvander@2306
   234
dvander@2306
   235
	if (g_TraceHandle != 0)
dvander@2306
   236
	{
dvander@2306
   237
		if ((err = handlesys->RemoveType(g_TraceHandle, myself->GetIdentity())) != true)
dvander@2306
   238
		{
dvander@2306
   239
			g_pSM->LogError(myself, "Could not remove trace handle (type=%x, err=%d)", g_TraceHandle, err);
dvander@2306
   240
		}
dvander@2306
   241
	}
dvander@950
   242
}
dvander@950
   243
ds@783
   244
bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
ds@783
   245
{
faluco@1560
   246
	GET_V_IFACE_ANY(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
faluco@1560
   247
	GET_V_IFACE_ANY(GetEngineFactory, engsound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION);
faluco@1560
   248
	GET_V_IFACE_ANY(GetEngineFactory, enginetrace, IEngineTrace, INTERFACEVERSION_ENGINETRACE_SERVER);
faluco@1560
   249
	GET_V_IFACE_ANY(GetEngineFactory, netstringtables, INetworkStringTableContainer, INTERFACENAME_NETWORKSTRINGTABLESERVER);
skamonkey@3854
   250
#if SOURCE_ENGINE != SE_DOTA
faluco@1560
   251
	GET_V_IFACE_ANY(GetEngineFactory, pluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS);
skamonkey@3854
   252
#endif
faluco@1560
   253
	GET_V_IFACE_ANY(GetServerFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
faluco@1560
   254
	GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER);
faluco@1560
   255
	GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER);
faluco@1560
   256
	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
ds@783
   257
skamonkey@3280
   258
#if SOURCE_ENGINE >= SE_ORANGEBOX
skamonkey@3280
   259
	GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
skamonkey@3280
   260
#endif
skamonkey@3280
   261
ds@2400
   262
	gpGlobals = ismm->GetCGlobals();
faluco@1735
   263
	enginePatch = SH_GET_CALLCLASS(engine);
faluco@1735
   264
	enginesoundPatch = SH_GET_CALLCLASS(engsound);
faluco@1735
   265
ds@783
   266
	return true;
ds@783
   267
}
ds@783
   268
ds@783
   269
void SDKTools::SDK_OnAllLoaded()
ds@783
   270
{
ds@783
   271
	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
ds@1065
   272
dvander@1757
   273
	if (!g_pBinTools)
dvander@1757
   274
	{
dvander@1757
   275
		return;
dvander@1757
   276
	}
dvander@1757
   277
faluco@1031
   278
	g_TEManager.Initialize();
faluco@1255
   279
	s_TempEntHooks.Initialize();
faluco@1735
   280
	s_SoundHooks.Initialize();
pred@2711
   281
	g_Hooks.Initialize();
ds@1240
   282
	InitializeValveGlobals();
ds@783
   283
}
ds@783
   284
skamonkey@3816
   285
void SDKTools::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
skamonkey@3816
   286
{
skamonkey@3816
   287
	InitTeamNatives();
skamonkey@3816
   288
	GetResourceEntity();
skamonkey@3816
   289
}
skamonkey@3816
   290
ds@783
   291
bool SDKTools::QueryRunning(char *error, size_t maxlength)
ds@783
   292
{
ds@783
   293
	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
ds@783
   294
ds@783
   295
	return true;
ds@783
   296
}
dvander@1023
   297
dvander@1023
   298
bool SDKTools::QueryInterfaceDrop(SMInterface *pInterface)
dvander@1023
   299
{
dvander@1023
   300
	if (pInterface == g_pBinTools)
dvander@1023
   301
	{
dvander@1023
   302
		return false;
dvander@1023
   303
	}
dvander@1023
   304
dvander@1023
   305
	return IExtensionInterface::QueryInterfaceDrop(pInterface);
dvander@1023
   306
}
dvander@1023
   307
dvander@1023
   308
void SDKTools::NotifyInterfaceDrop(SMInterface *pInterface)
dvander@1023
   309
{
faluco@1560
   310
	SourceHook::List<ValveCall *>::iterator iter;
dvander@1023
   311
	for (iter = g_RegCalls.begin();
dvander@1023
   312
		iter != g_RegCalls.end();
dvander@1023
   313
		iter++)
dvander@1023
   314
	{
dvander@1023
   315
		delete (*iter);
dvander@1023
   316
	}
dvander@1023
   317
	g_RegCalls.clear();
dvander@1169
   318
	ShutdownHelpers();
dvander@1023
   319
faluco@1031
   320
	g_TEManager.Shutdown();
faluco@1255
   321
	s_TempEntHooks.Shutdown();
faluco@1498
   322
faluco@1498
   323
	if (g_pAcceptInput)
faluco@1498
   324
	{
faluco@1498
   325
		g_pAcceptInput->Destroy();
faluco@1498
   326
		g_pAcceptInput = NULL;
faluco@1498
   327
	}
dvander@1023
   328
}
dvander@1052
   329
dvander@1052
   330
bool SDKTools::RegisterConCommandBase(ConCommandBase *pVar)
dvander@1052
   331
{
faluco@1560
   332
#if defined METAMOD_PLAPI_VERSION
faluco@1560
   333
	return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar);
faluco@1560
   334
#else
dvander@1052
   335
	return g_SMAPI->RegisterConCmdBase(g_PLAPI, pVar);
faluco@1560
   336
#endif
dvander@1052
   337
}
faluco@1262
   338
faluco@1262
   339
bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
faluco@1262
   340
{
faluco@1262
   341
	const char *name;
faluco@1262
   342
	char key[32];
faluco@1262
   343
	int count, n = 1;
faluco@1262
   344
faluco@1262
   345
	if (!(name=g_pGameConf->GetKeyValue("SlapSoundCount")))
faluco@1262
   346
	{
faluco@1262
   347
		RETURN_META_VALUE(MRES_IGNORED, true);
faluco@1262
   348
	}
faluco@1262
   349
faluco@1262
   350
	count = atoi(name);
faluco@1262
   351
faluco@1262
   352
	while (n <= count)
faluco@1262
   353
	{
faluco@1262
   354
		snprintf(key, sizeof(key), "SlapSound%d", n);
faluco@1262
   355
		if ((name=g_pGameConf->GetKeyValue(key)))
faluco@1262
   356
		{
faluco@1262
   357
			engsound->PrecacheSound(name, true);
faluco@1262
   358
		}
faluco@1262
   359
		n++;
faluco@1262
   360
	}
faluco@1262
   361
faluco@1262
   362
	RETURN_META_VALUE(MRES_IGNORED, true);
faluco@1262
   363
}
dvander@1628
   364
dvander@1628
   365
bool SDKTools::ProcessCommandTarget(cmd_target_info_t *info)
dvander@1628
   366
{
dvander@1628
   367
	IGamePlayer *pAdmin = info->admin ? playerhelpers->GetGamePlayer(info->admin) : NULL;
dvander@1628
   368
dvander@2838
   369
	if (strcmp(info->pattern, "@aim") == 0)
dvander@1628
   370
	{
dvander@2838
   371
		/* The server can't aim, of course. */
dvander@2838
   372
		if (pAdmin == NULL)
dvander@2838
   373
		{
dvander@2838
   374
			return false;
dvander@2838
   375
		}
dvander@2838
   376
dvander@2838
   377
		int player_index;
dvander@2838
   378
		if ((player_index = GetClientAimTarget(pAdmin->GetEdict(), true)) < 1)
dvander@2838
   379
		{
dvander@2838
   380
			info->reason = COMMAND_TARGET_NONE;
dvander@2838
   381
			info->num_targets = 0;
dvander@2838
   382
			return true;
dvander@2838
   383
		}
dvander@2838
   384
dvander@2838
   385
		IGamePlayer *pTarget = playerhelpers->GetGamePlayer(player_index);
dvander@2838
   386
dvander@2838
   387
		if (pTarget == NULL)
dvander@2838
   388
		{
dvander@2838
   389
			info->reason = COMMAND_TARGET_NONE;
dvander@2838
   390
			info->num_targets = 0;
dvander@2838
   391
			return true;
dvander@2838
   392
		}
dvander@2838
   393
dvander@2838
   394
		info->reason = playerhelpers->FilterCommandTarget(pAdmin, pTarget, info->flags);
dvander@2838
   395
		if (info->reason != COMMAND_TARGET_VALID)
dvander@2838
   396
		{
dvander@2838
   397
			info->num_targets = 0;
dvander@2838
   398
			return true;
dvander@2838
   399
		}
dvander@1628
   400
dvander@2838
   401
		info->targets[0] = player_index;
dvander@2838
   402
		info->num_targets = 1;
dvander@2838
   403
		info->reason = COMMAND_TARGET_VALID;
dvander@2838
   404
		info->target_name_style = COMMAND_TARGETNAME_RAW;
dvander@2838
   405
		snprintf(info->target_name, info->target_name_maxlength, "%s", pTarget->GetName());
dvander@2838
   406
		return true;
dvander@2838
   407
	}
dvander@2838
   408
	else if (strcmp(info->pattern, "@spec") == 0)
dvander@1628
   409
	{
dvander@2838
   410
		const char *teamname = tools_GetTeamName(1);
dvander@2838
   411
		if (strcasecmp(teamname, "spectator") != 0)
dvander@2838
   412
			return false;
dvander@1757
   413
		info->num_targets = 0;
dvander@2838
   414
		for (int i = 1; i <= playerhelpers->GetMaxClients(); i++)
dvander@2838
   415
		{
dvander@2838
   416
			IGamePlayer *player = playerhelpers->GetGamePlayer(i);
dvander@2838
   417
			if (player == NULL || !player->IsInGame())
dvander@2838
   418
				continue;
dvander@2838
   419
			IPlayerInfo *plinfo = player->GetPlayerInfo();
dvander@2838
   420
			if (plinfo == NULL)
dvander@2838
   421
				continue;
dvander@2838
   422
			if (plinfo->GetTeamIndex() == 1 &&
dvander@2838
   423
			    playerhelpers->FilterCommandTarget(pAdmin, player, info->flags) ==
dvander@2838
   424
				COMMAND_TARGET_VALID)
dvander@2838
   425
			{
dvander@2838
   426
				info->targets[info->num_targets++] = i;
dvander@2838
   427
			}
dvander@2838
   428
		}
dvander@2838
   429
		info->reason = info->num_targets > 0 ? COMMAND_TARGET_VALID : COMMAND_TARGET_EMPTY_FILTER;
dvander@2838
   430
		info->target_name_style = COMMAND_TARGETNAME_ML;
dvander@2838
   431
		snprintf(info->target_name, info->target_name_maxlength, "all spectators");
dvander@1757
   432
		return true;
dvander@1628
   433
	}
dvander@1628
   434
dvander@2838
   435
	return false;
dvander@1628
   436
}
dvander@2503
   437
dvander@2790
   438
const char *SDKTools::GetExtensionVerString()
pred@2711
   439
{
asherkin@3630
   440
	return SM_VERSION_STRING;
dvander@2783
   441
}
dvander@2783
   442
dvander@2790
   443
const char *SDKTools::GetExtensionDateString()
dvander@2783
   444
{
dvander@2783
   445
	return SM_BUILD_TIMESTAMP;
pred@2711
   446
}
pred@2711
   447
dvander@2786
   448
void SDKTools::OnClientPutInServer(int client)
dvander@2786
   449
{
dvander@2786
   450
	g_Hooks.OnClientPutInServer(client);
dvander@2786
   451
}
dvander@2786
   452
dvander@2503
   453
class SDKTools_API : public ISDKTools
dvander@2503
   454
{
dvander@2503
   455
public:
dvander@2503
   456
	virtual const char *GetInterfaceName()
dvander@2503
   457
	{
dvander@2503
   458
		return SMINTERFACE_SDKTOOLS_NAME;
dvander@2503
   459
	}
dvander@2503
   460
dvander@2503
   461
	virtual unsigned int GetInterfaceVersion()
dvander@2503
   462
	{
dvander@2503
   463
		return SMINTERFACE_SDKTOOLS_VERSION;
dvander@2503
   464
	}
dvander@2503
   465
dvander@2503
   466
	virtual IServer *GetIServer()
dvander@2503
   467
	{
dvander@2503
   468
		return iserver;
dvander@2503
   469
	}
skamonkey@3157
   470
	
skamonkey@3157
   471
	virtual void *GetGameRules()
skamonkey@3157
   472
	{
skamonkey@3157
   473
		if (!g_pGameRules)
skamonkey@3157
   474
			return NULL;
skamonkey@3157
   475
		
skamonkey@3157
   476
		return *g_pGameRules;
skamonkey@3157
   477
	}
dvander@2503
   478
} g_SDKTools_API;
dvander@2503
   479
dvander@2503
   480
static void InitSDKToolsAPI()
dvander@2503
   481
{
dvander@2503
   482
	g_pSDKTools = &g_SDKTools_API;
dvander@2503
   483
	sharesys->AddInterface(myself, g_pSDKTools);
dvander@2503
   484
}