extensions/cstrike/extension.cpp
author David Anderson <dvander@alliedmods.net>
Mon Dec 30 17:51:00 2013 -0500 (2013-12-30)
changeset 4188 89782d5fc91b
parent 3819 d17aed3d46bf
permissions -rw-r--r--
Move versioning to a static library to improve trivial build speed (bug 5997 part 9, r=ds).
faluco@1441
     1
/**
faluco@1441
     2
 * vim: set ts=4 :
faluco@1441
     3
 * =============================================================================
faluco@1441
     4
 * SourceMod Counter-Strike:Source Extension
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
faluco@1441
     6
 * =============================================================================
faluco@1441
     7
 *
faluco@1441
     8
 * This program is free software; you can redistribute it and/or modify it under
faluco@1441
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
faluco@1441
    10
 * Free Software Foundation.
faluco@1441
    11
 * 
faluco@1441
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
faluco@1441
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
faluco@1441
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
faluco@1441
    15
 * details.
faluco@1441
    16
 *
faluco@1441
    17
 * You should have received a copy of the GNU General Public License along with
faluco@1441
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
faluco@1441
    19
 *
faluco@1441
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
faluco@1441
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
faluco@1441
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
faluco@1441
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
faluco@1441
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
faluco@1441
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
faluco@1441
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
faluco@1441
    27
 * or <http://www.sourcemod.net/license.php>.
faluco@1441
    28
 *
faluco@1441
    29
 * Version: $Id$
faluco@1441
    30
 */
faluco@1441
    31
dvander@2783
    32
#include <sourcemod_version.h>
faluco@1441
    33
#include "extension.h"
faluco@1441
    34
#include "RegNatives.h"
dvander@1459
    35
#include "timeleft.h"
dvander@1756
    36
#include "iplayerinfo.h"
rgr_02@3313
    37
#include "ISDKTools.h"
rgr_02@3313
    38
#include "forwards.h"
faluco@1441
    39
faluco@1441
    40
/**
faluco@1441
    41
 * @file extension.cpp
faluco@1441
    42
 * @brief Implement extension code here.
faluco@1441
    43
 */
faluco@1441
    44
dvander@1459
    45
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
dvander@1459
    46
faluco@1441
    47
CStrike g_CStrike;		/**< Global singleton for extension's main interface */
faluco@1441
    48
IBinTools *g_pBinTools = NULL;
faluco@1441
    49
IGameConfig *g_pGameConf = NULL;
dvander@1459
    50
IGameEventManager2 *gameevents = NULL;
dvander@1459
    51
bool hooked_everything = false;
dvander@1692
    52
int g_msgHintText = -1;
faluco@1441
    53
faluco@1441
    54
SMEXT_LINK(&g_CStrike);
faluco@1441
    55
faluco@1441
    56
extern sp_nativeinfo_t g_CSNatives[];
faluco@1441
    57
rgr_02@3313
    58
ISDKTools *g_pSDKTools = NULL;
rgr_02@3313
    59
faluco@1441
    60
bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
faluco@1441
    61
{
rgr_02@3519
    62
	if (strcmp(g_pSM->GetGameFolderName(), "cstrike") != 0 && strcmp(g_pSM->GetGameFolderName(), "csgo") != 0)
pred@2069
    63
	{
rgr_02@3519
    64
		snprintf(error, maxlength, "Cannot Load Cstrike Extension on mods other than CS:S and CS:GO");
pred@2069
    65
		return false;
pred@2069
    66
	}
pred@2069
    67
faluco@1441
    68
	sharesys->AddDependency(myself, "bintools.ext", true, true);
aangione@3406
    69
	sharesys->AddDependency(myself, "sdktools.ext", false, true);
faluco@1441
    70
dvander@1459
    71
	char conf_error[255];
dvander@1459
    72
	if (!gameconfs->LoadGameConfigFile("sm-cstrike.games", &g_pGameConf, conf_error, sizeof(conf_error)))
faluco@1441
    73
	{
dvander@1459
    74
		if (error)
dvander@1459
    75
		{
rgr_02@3519
    76
			snprintf(error, maxlength, "Could not read sm-cstrike.games: %s", conf_error);
dvander@1459
    77
		}
faluco@1441
    78
		return false;
faluco@1441
    79
	}
faluco@1441
    80
faluco@1441
    81
	sharesys->AddNatives(myself, g_CSNatives);
dvander@1573
    82
	sharesys->RegisterLibrary(myself, "cstrike");
rgr_02@3313
    83
	plsys->AddPluginsListener(this);
faluco@1441
    84
dvander@1756
    85
	playerhelpers->RegisterCommandTargetProcessor(this);
dvander@1756
    86
rgr_02@3313
    87
	CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
rgr_02@3313
    88
rgr_02@3313
    89
	g_pHandleBuyForward = forwards->CreateForward("CS_OnBuyCommand", ET_Event, 2, NULL, Param_Cell, Param_String);
rgr_02@3313
    90
	g_pPriceForward = forwards->CreateForward("CS_OnGetWeaponPrice", ET_Event, 3, NULL, Param_Cell, Param_String, Param_CellByRef);
rgr_02@3313
    91
	g_pTerminateRoundForward = forwards->CreateForward("CS_OnTerminateRound", ET_Event, 2, NULL, Param_FloatByRef, Param_CellByRef);
rgr_02@3313
    92
	g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 2, NULL, Param_Cell, Param_Cell);
rgr_02@3313
    93
rgr_02@3313
    94
rgr_02@3313
    95
	m_TerminateRoundDetourEnabled = false;
rgr_02@3313
    96
	m_WeaponPriceDetourEnabled = false;
rgr_02@3313
    97
	m_HandleBuyDetourEnabled = false;
rgr_02@3313
    98
	m_CSWeaponDetourEnabled = false;
rgr_02@3313
    99
faluco@1441
   100
	return true;
faluco@1441
   101
}
faluco@1441
   102
dvander@1459
   103
bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
dvander@1459
   104
{
faluco@1552
   105
	GET_V_IFACE_CURRENT(GetEngineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
faluco@1552
   106
	GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
dvander@1459
   107
dvander@1459
   108
	return true;
dvander@1459
   109
}
dvander@1459
   110
faluco@1441
   111
void CStrike::SDK_OnUnload()
faluco@1441
   112
{
dvander@1459
   113
	if (hooked_everything)
dvander@1459
   114
	{
dvander@1459
   115
		gameevents->RemoveListener(&g_TimeLeftEvents);
kyle@3819
   116
		SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(&g_TimeLeftEvents, &TimeLeftEvents::LevelInit), true);
dvander@1459
   117
		hooked_everything = false;
dvander@1459
   118
	}
faluco@1441
   119
	g_RegNatives.UnregisterAll();
faluco@1441
   120
	gameconfs->CloseGameConfigFile(g_pGameConf);
rgr_02@3313
   121
	plsys->RemovePluginsListener(this);
dvander@1756
   122
	playerhelpers->UnregisterCommandTargetProcessor(this);
rgr_02@3313
   123
	forwards->ReleaseForward(g_pHandleBuyForward);
rgr_02@3313
   124
	forwards->ReleaseForward(g_pPriceForward);
rgr_02@3313
   125
	forwards->ReleaseForward(g_pTerminateRoundForward);
rgr_02@3313
   126
	forwards->ReleaseForward(g_pCSWeaponDropForward);
faluco@1441
   127
}
faluco@1441
   128
faluco@1441
   129
void CStrike::SDK_OnAllLoaded()
faluco@1441
   130
{
rgr_02@3313
   131
	SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
rgr_02@3313
   132
	if (g_pSDKTools == NULL)
rgr_02@3313
   133
	{
rgr_02@3313
   134
		smutils->LogError(myself, "SDKTools interface not found. TerminateRound native disabled.");
rgr_02@3313
   135
	}
rgr_02@3313
   136
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3313
   137
	{
rgr_02@3313
   138
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3313
   139
		smutils->LogError(myself, "SDKTools interface is outdated. TerminateRound native disabled.");
rgr_02@3313
   140
	}
dvander@1459
   141
	gameevents->AddListener(&g_TimeLeftEvents, "round_start", true);
dvander@1459
   142
	gameevents->AddListener(&g_TimeLeftEvents, "round_end", true);
kyle@3819
   143
	SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(&g_TimeLeftEvents, &TimeLeftEvents::LevelInit), true);
dvander@1459
   144
	hooked_everything = true;
dvander@1459
   145
faluco@1441
   146
	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
faluco@1441
   147
}
faluco@1441
   148
faluco@1441
   149
bool CStrike::QueryRunning(char *error, size_t maxlength)
faluco@1441
   150
{
faluco@1441
   151
	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
faluco@1441
   152
faluco@1441
   153
	return true;
faluco@1441
   154
}
faluco@1441
   155
faluco@1441
   156
bool CStrike::QueryInterfaceDrop(SMInterface *pInterface)
faluco@1441
   157
{
faluco@1441
   158
	if (pInterface == g_pBinTools)
faluco@1441
   159
	{
faluco@1441
   160
		return false;
faluco@1441
   161
	}
faluco@1441
   162
faluco@1441
   163
	return IExtensionInterface::QueryInterfaceDrop(pInterface);
faluco@1441
   164
}
faluco@1441
   165
faluco@1441
   166
void CStrike::NotifyInterfaceDrop(SMInterface *pInterface)
faluco@1441
   167
{
faluco@1441
   168
	g_RegNatives.UnregisterAll();
faluco@1441
   169
}
dvander@1756
   170
dvander@1756
   171
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
dvander@1756
   172
{
dvander@1756
   173
	va_list ap;
dvander@1756
   174
	va_start(ap, fmt);
dvander@1756
   175
	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
dvander@1756
   176
	va_end(ap);
dvander@1756
   177
dvander@1756
   178
	if (len >= maxlength)
dvander@1756
   179
	{
dvander@1756
   180
		buffer[maxlength - 1] = '\0';
dvander@1756
   181
		return (maxlength - 1);
dvander@1756
   182
	}
dvander@1756
   183
	else
dvander@1756
   184
	{
dvander@1756
   185
		return len;
dvander@1756
   186
	}
dvander@1756
   187
}
dvander@1756
   188
dvander@1756
   189
bool CStrike::ProcessCommandTarget(cmd_target_info_t *info)
dvander@1756
   190
{
dvander@1756
   191
	int max_clients;
dvander@1756
   192
	IPlayerInfo *pInfo;
dvander@1756
   193
	unsigned int team_index = 0;
dvander@1756
   194
	IGamePlayer *pPlayer, *pAdmin;
dvander@1756
   195
dvander@1756
   196
	if ((info->flags & COMMAND_FILTER_NO_MULTI) == COMMAND_FILTER_NO_MULTI)
dvander@1756
   197
	{
dvander@1756
   198
		return false;
dvander@1756
   199
	}
dvander@1756
   200
dvander@1756
   201
	if (info->admin)
dvander@1756
   202
	{
dvander@1756
   203
		if ((pAdmin = playerhelpers->GetGamePlayer(info->admin)) == NULL)
dvander@1756
   204
		{
dvander@1756
   205
			return false;
dvander@1756
   206
		}
dvander@1756
   207
		if (!pAdmin->IsInGame())
dvander@1756
   208
		{
dvander@1756
   209
			return false;
dvander@1756
   210
		}
dvander@1756
   211
	}
dvander@1756
   212
	else
dvander@1756
   213
	{
dvander@1756
   214
		pAdmin = NULL;
dvander@1756
   215
	}
dvander@1756
   216
dvander@1756
   217
	if (strcmp(info->pattern, "@ct") == 0 || strcmp(info->pattern, "@cts") == 0)
dvander@1756
   218
	{
dvander@1756
   219
		team_index = 3;
dvander@1756
   220
	}
dvander@1756
   221
	else if (strcmp(info->pattern, "@t") == 0 || strcmp(info->pattern, "@ts") == 0)
dvander@1756
   222
	{
dvander@1756
   223
		team_index = 2;
dvander@1756
   224
	}
dvander@1781
   225
	else
dvander@1781
   226
	{
dvander@1781
   227
		return false;
dvander@1781
   228
	}
dvander@1756
   229
dvander@1756
   230
	info->num_targets = 0;
dvander@1756
   231
dvander@1756
   232
	max_clients = playerhelpers->GetMaxClients();
dvander@1756
   233
	for (int i = 1; 
dvander@1756
   234
		 i <= max_clients && (cell_t)info->num_targets < info->max_targets; 
dvander@1756
   235
		 i++)
dvander@1756
   236
	{
dvander@1756
   237
		if ((pPlayer = playerhelpers->GetGamePlayer(i)) == NULL)
dvander@1756
   238
		{
dvander@1756
   239
			continue;
dvander@1756
   240
		}
dvander@1756
   241
		if (!pPlayer->IsInGame())
dvander@1756
   242
		{
dvander@1756
   243
			continue;
dvander@1756
   244
		}
dvander@1756
   245
		if ((pInfo = pPlayer->GetPlayerInfo()) == NULL)
dvander@1756
   246
		{
dvander@1756
   247
			continue;
dvander@1756
   248
		}
dvander@1758
   249
		if (pInfo->GetTeamIndex() != (int)team_index)
dvander@1756
   250
		{
dvander@1756
   251
			continue;
dvander@1756
   252
		}
dvander@1756
   253
		if (playerhelpers->FilterCommandTarget(pAdmin, pPlayer, info->flags) 
dvander@1756
   254
			!= COMMAND_TARGET_VALID)
dvander@1756
   255
		{
dvander@1756
   256
			continue;
dvander@1756
   257
		}
dvander@1756
   258
		info->targets[info->num_targets] = i;
dvander@1756
   259
		info->num_targets++;
dvander@1756
   260
	}
dvander@1756
   261
dvander@1756
   262
	if (info->num_targets == 0)
dvander@1756
   263
	{
dvander@1756
   264
		info->reason = COMMAND_TARGET_EMPTY_FILTER;
dvander@1756
   265
	}
dvander@1756
   266
	else
dvander@1756
   267
	{
dvander@1756
   268
		info->reason = COMMAND_TARGET_VALID;
dvander@1756
   269
	}
dvander@1756
   270
dvander@1756
   271
	info->target_name_style = COMMAND_TARGETNAME_RAW;
dvander@1756
   272
	if (team_index == 2)
dvander@1756
   273
	{
dvander@1756
   274
		UTIL_Format(info->target_name, info->target_name_maxlength, "Terrorists");
dvander@1756
   275
	}
dvander@1756
   276
	else if (team_index == 3)
dvander@1756
   277
	{
dvander@1756
   278
		UTIL_Format(info->target_name, info->target_name_maxlength, "CTs");
dvander@1756
   279
	}
dvander@1756
   280
dvander@1756
   281
	return true;
dvander@1756
   282
}
dvander@2783
   283
dvander@2790
   284
const char *CStrike::GetExtensionVerString()
dvander@2783
   285
{
dvander@4188
   286
	return SOURCEMOD_VERSION;
dvander@2783
   287
}
dvander@2783
   288
dvander@2790
   289
const char *CStrike::GetExtensionDateString()
dvander@2783
   290
{
dvander@4188
   291
	return SOURCEMOD_BUILD_TIME;
dvander@2783
   292
}
dvander@2783
   293
rgr_02@3313
   294
void CStrike::OnPluginLoaded(IPlugin *plugin)
rgr_02@3313
   295
{
rgr_02@3313
   296
	if (!m_WeaponPriceDetourEnabled && g_pPriceForward->GetFunctionCount())
rgr_02@3313
   297
	{
rgr_02@3313
   298
		m_WeaponPriceDetourEnabled = CreateWeaponPriceDetour();
rgr_02@3313
   299
		if (m_WeaponPriceDetourEnabled)
rgr_02@3313
   300
			m_HandleBuyDetourEnabled = true;
rgr_02@3313
   301
	}
rgr_02@3313
   302
	if (!m_TerminateRoundDetourEnabled && g_pTerminateRoundForward->GetFunctionCount())
rgr_02@3313
   303
	{
rgr_02@3313
   304
		m_TerminateRoundDetourEnabled = CreateTerminateRoundDetour();
rgr_02@3313
   305
	}
rgr_02@3313
   306
	if (!m_HandleBuyDetourEnabled && g_pHandleBuyForward->GetFunctionCount())
rgr_02@3313
   307
	{
rgr_02@3313
   308
		m_HandleBuyDetourEnabled = CreateHandleBuyDetour();
rgr_02@3313
   309
	}
rgr_02@3313
   310
	if (!m_CSWeaponDetourEnabled && g_pCSWeaponDropForward->GetFunctionCount())
rgr_02@3313
   311
	{
rgr_02@3313
   312
		m_CSWeaponDetourEnabled = CreateCSWeaponDropDetour();
rgr_02@3313
   313
	}
rgr_02@3313
   314
}
rgr_02@3313
   315
rgr_02@3313
   316
void CStrike::OnPluginUnloaded(IPlugin *plugin)
rgr_02@3313
   317
{
rgr_02@3313
   318
	if (m_WeaponPriceDetourEnabled && !g_pPriceForward->GetFunctionCount())
rgr_02@3313
   319
	{
rgr_02@3313
   320
		RemoveWeaponPriceDetour();
rgr_02@3313
   321
		m_WeaponPriceDetourEnabled = false;
rgr_02@3313
   322
	}
rgr_02@3313
   323
	if (m_TerminateRoundDetourEnabled && !g_pTerminateRoundForward->GetFunctionCount())
rgr_02@3313
   324
	{
rgr_02@3313
   325
		RemoveTerminateRoundDetour();
rgr_02@3313
   326
		m_TerminateRoundDetourEnabled = false;
rgr_02@3313
   327
	}
rgr_02@3313
   328
	if (m_HandleBuyDetourEnabled && !g_pHandleBuyForward->GetFunctionCount())
rgr_02@3313
   329
	{
rgr_02@3313
   330
		RemoveHandleBuyDetour();
rgr_02@3313
   331
		m_HandleBuyDetourEnabled = false;
rgr_02@3313
   332
	}
rgr_02@3313
   333
	if (m_CSWeaponDetourEnabled && !g_pCSWeaponDropForward->GetFunctionCount())
rgr_02@3313
   334
	{
rgr_02@3313
   335
		RemoveCSWeaponDropDetour();
rgr_02@3313
   336
		m_CSWeaponDetourEnabled = false;;
rgr_02@3313
   337
	}
rgr_02@3313
   338
}