extensions/sdktools/tenatives.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4344 c445c3266192
permissions -rw-r--r--
Update CS:GO team score gamedata.
     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 "tempents.h"
    33 #include "CellRecipientFilter.h"
    34 #include <IForwardSys.h>
    35 
    36 SH_DECL_HOOK5_void(IVEngineServer, PlaybackTempEntity, SH_NOATTRIB, 0, IRecipientFilter &, float, const void *, const SendTable *, int);
    37 
    38 CellRecipientFilter g_TERecFilter;
    39 TempEntityInfo *g_CurrentTE = NULL;
    40 int g_TEPlayers[SM_MAXPLAYERS+1];
    41 bool tenatives_initialized = false;
    42 
    43 /*************************
    44 *                        *
    45 * Temp Entity Hook Class *
    46 *                        *
    47 **************************/
    48 
    49 void TempEntHooks::Initialize()
    50 {
    51 	m_TEHooks = adtfactory->CreateBasicTrie();
    52 	plsys->AddPluginsListener(this);
    53 	tenatives_initialized = true;
    54 }
    55 
    56 void TempEntHooks::Shutdown()
    57 {
    58 	if (!tenatives_initialized)
    59 	{
    60 		return;
    61 	}
    62 
    63 	plsys->RemovePluginsListener(this);
    64 	SourceHook::List<TEHookInfo *>::iterator iter;
    65 	for (iter=m_HookInfo.begin(); iter!=m_HookInfo.end(); iter++)
    66 	{
    67 		delete (*iter);
    68 	}
    69 	if (m_HookCount)
    70 	{
    71 		m_HookCount = 1;
    72 		_DecRefCounter();
    73 	}
    74 	m_TEHooks->Destroy();
    75 	tenatives_initialized = false;
    76 }
    77 
    78 void TempEntHooks::OnPluginUnloaded(IPlugin *plugin)
    79 {
    80 	SourceHook::List<TEHookInfo *>::iterator iter = m_HookInfo.begin();
    81 	IPluginContext *pContext = plugin->GetBaseContext();
    82 
    83 	/* For each hook list... */
    84 	while (iter != m_HookInfo.end())
    85 	{
    86 		SourceHook::List<IPluginFunction *>::iterator f_iter = (*iter)->lst.begin();
    87 
    88 		/* Find the hooks on the given temp entity */
    89 		while (f_iter != (*iter)->lst.end())
    90 		{
    91 			/* If it matches, remove it and dec the ref count */
    92 			if ((*f_iter)->GetParentContext() == pContext)
    93 			{
    94 				f_iter = (*iter)->lst.erase(f_iter);
    95 				_DecRefCounter();
    96 			}
    97 			else
    98 			{
    99 				f_iter++;
   100 			}
   101 		}
   102 
   103 		/* If there are no more hooks left, we can safely 
   104 		 * remove it from the cache and remove its list.
   105 		 */
   106 		if ((*iter)->lst.size() == 0)
   107 		{
   108 			m_TEHooks->Delete((*iter)->te->GetName());
   109 			delete (*iter);
   110 			iter = m_HookInfo.erase(iter);
   111 		}
   112 		else
   113 		{
   114 			iter++;
   115 		}
   116 	}
   117 }
   118 
   119 void TempEntHooks::_IncRefCounter()
   120 {
   121 	if (m_HookCount++ == 0)
   122 	{
   123 		SH_ADD_HOOK(IVEngineServer, PlaybackTempEntity, engine, SH_MEMBER(this, &TempEntHooks::OnPlaybackTempEntity), false);
   124 	}
   125 }
   126 
   127 void TempEntHooks::_DecRefCounter()
   128 {
   129 	if (--m_HookCount == 0)
   130 	{
   131 		SH_REMOVE_HOOK(IVEngineServer, PlaybackTempEntity, engine, SH_MEMBER(this, &TempEntHooks::OnPlaybackTempEntity), false);
   132 	}
   133 }
   134 
   135 size_t TempEntHooks::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
   136 {
   137 	size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
   138 
   139 	for (size_t i=0; i<size; i++)
   140 	{
   141 		int index;
   142 #if SOURCE_ENGINE == SE_DOTA
   143 		index = pFilter->GetRecipientIndex(i).Get();
   144 #else
   145 		index = pFilter->GetRecipientIndex(i);
   146 #endif
   147 		pl_array[i] = index;
   148 	}
   149 
   150 	return size;
   151 }
   152 
   153 bool TempEntHooks::AddHook(const char *name, IPluginFunction *pFunc)
   154 {
   155 	TEHookInfo *pInfo;
   156 
   157 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   158 	{
   159 		pInfo->lst.push_back(pFunc);
   160 	} else {
   161 		TempEntityInfo *te;
   162 		if (!(te=g_TEManager.GetTempEntityInfo(name)))
   163 		{
   164 			return false;
   165 		}
   166 
   167 		pInfo = new TEHookInfo;
   168 		pInfo->te = te;
   169 		pInfo->lst.push_back(pFunc);
   170 
   171 		m_TEHooks->Insert(name, reinterpret_cast<void *>(pInfo));
   172 		m_HookInfo.push_back(pInfo);
   173 	}
   174 
   175 	_IncRefCounter();
   176 
   177 	return true;
   178 }
   179 
   180 bool TempEntHooks::RemoveHook(const char *name, IPluginFunction *pFunc)
   181 {
   182 	TEHookInfo *pInfo;
   183 
   184 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   185 	{
   186 		SourceHook::List<IPluginFunction *>::iterator iter;
   187 		if ((iter=pInfo->lst.find(pFunc)) != pInfo->lst.end())
   188 		{
   189 			pInfo->lst.erase(iter);
   190 			if (pInfo->lst.empty())
   191 			{
   192 				m_HookInfo.remove(pInfo);
   193 				m_TEHooks->Delete(name);
   194 				delete pInfo;
   195 			}
   196 			_DecRefCounter();
   197 		} else {
   198 			return false;
   199 		}
   200 	} else {
   201 		return false;
   202 	}
   203 
   204 	return true;
   205 }
   206 
   207 void TempEntHooks::OnPlaybackTempEntity(IRecipientFilter &filter, float delay, const void *pSender, const SendTable *pST, int classID)
   208 {
   209 	TEHookInfo *pInfo;
   210 	const char *name = g_TEManager.GetNameFromThisPtr(const_cast<void *>(pSender));
   211 
   212 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   213 	{
   214 		SourceHook::List<IPluginFunction *>::iterator iter;
   215 		IPluginFunction *pFunc;
   216 		size_t size;
   217 		cell_t res = static_cast<ResultType>(Pl_Continue);
   218 
   219 		TempEntityInfo *oldinfo = g_CurrentTE;
   220 		g_CurrentTE = pInfo->te;
   221 		size = _FillInPlayers(g_TEPlayers, &filter);
   222 
   223 		for (iter=pInfo->lst.begin(); iter!=pInfo->lst.end(); iter++)
   224 		{
   225 			pFunc = (*iter);
   226 			pFunc->PushString(name);
   227 			pFunc->PushArray(g_TEPlayers, size);
   228 			pFunc->PushCell(size);
   229 			pFunc->PushFloat(delay);
   230 			pFunc->Execute(&res);
   231 
   232 			if (res != Pl_Continue)
   233 			{
   234 				g_CurrentTE = oldinfo;
   235 				RETURN_META(MRES_SUPERCEDE);
   236 			}
   237 		}
   238 
   239 		g_CurrentTE = oldinfo;
   240 		RETURN_META(MRES_IGNORED);
   241 	}
   242 }
   243 
   244 /**********************
   245 *                     *
   246 * Temp Entity Natives *
   247 *                     *
   248 ***********************/
   249 
   250 TempEntHooks s_TempEntHooks;
   251 
   252 static cell_t smn_TEStart(IPluginContext *pContext, const cell_t *params)
   253 {
   254 	if (!g_TEManager.IsAvailable())
   255 	{
   256 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   257 	}
   258 
   259 	char *name;
   260 	pContext->LocalToString(params[1], &name);
   261 
   262 	g_CurrentTE = g_TEManager.GetTempEntityInfo(name);
   263 	if (!g_CurrentTE)
   264 	{
   265 		return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
   266 	}
   267 
   268 	return 1;
   269 }
   270 
   271 static cell_t smn_TEWriteNum(IPluginContext *pContext, const cell_t *params)
   272 {
   273 	if (!g_TEManager.IsAvailable())
   274 	{
   275 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   276 	}
   277 	if (!g_CurrentTE)
   278 	{
   279 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   280 	}
   281 
   282 	char *prop;
   283 	pContext->LocalToString(params[1], &prop);
   284 
   285 	if (!g_CurrentTE->TE_SetEntData(prop, params[2]))
   286 	{
   287 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   288 	}
   289 
   290 	return 1;
   291 }
   292 
   293 static cell_t smn_TEReadNum(IPluginContext *pContext, const cell_t *params)
   294 {
   295 	if (!g_TEManager.IsAvailable())
   296 	{
   297 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   298 	}
   299 	if (!g_CurrentTE)
   300 	{
   301 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   302 	}
   303 
   304 	char *prop;
   305 	int val;
   306 	pContext->LocalToString(params[1], &prop);
   307 
   308 	if (!g_CurrentTE->TE_GetEntData(prop, &val))
   309 	{
   310 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   311 	}
   312 
   313 	return val;
   314 }
   315 
   316 static cell_t smn_TE_WriteFloat(IPluginContext *pContext, const cell_t *params)
   317 {
   318 	if (!g_TEManager.IsAvailable())
   319 	{
   320 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   321 	}
   322 	if (!g_CurrentTE)
   323 	{
   324 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   325 	}
   326 
   327 	char *prop;
   328 	pContext->LocalToString(params[1], &prop);
   329 
   330 	if (!g_CurrentTE->TE_SetEntDataFloat(prop, sp_ctof(params[2])))
   331 	{
   332 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   333 	}
   334 
   335 	return 1;
   336 }
   337 
   338 static cell_t smn_TE_ReadFloat(IPluginContext *pContext, const cell_t *params)
   339 {
   340 	if (!g_TEManager.IsAvailable())
   341 	{
   342 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   343 	}
   344 	if (!g_CurrentTE)
   345 	{
   346 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   347 	}
   348 
   349 	char *prop;
   350 	float val;
   351 	pContext->LocalToString(params[1], &prop);
   352 
   353 	if (!g_CurrentTE->TE_GetEntDataFloat(prop, &val))
   354 	{
   355 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   356 	}
   357 
   358 	return sp_ftoc(val);
   359 }
   360 
   361 static cell_t smn_TEWriteVector(IPluginContext *pContext, const cell_t *params)
   362 {
   363 	if (!g_TEManager.IsAvailable())
   364 	{
   365 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   366 	}
   367 	if (!g_CurrentTE)
   368 	{
   369 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   370 	}
   371 
   372 	char *prop;
   373 	pContext->LocalToString(params[1], &prop);
   374 
   375 	cell_t *addr;
   376 	pContext->LocalToPhysAddr(params[2], &addr);
   377 	float vec[3] = {sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2])};
   378 
   379 	if (!g_CurrentTE->TE_SetEntDataVector(prop, vec))
   380 	{
   381 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   382 	}
   383 
   384 	return 1;
   385 }
   386 
   387 static cell_t smn_TEReadVector(IPluginContext *pContext, const cell_t *params)
   388 {
   389 	if (!g_TEManager.IsAvailable())
   390 	{
   391 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   392 	}
   393 	if (!g_CurrentTE)
   394 	{
   395 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   396 	}
   397 
   398 	char *prop;
   399 	pContext->LocalToString(params[1], &prop);
   400 
   401 	cell_t *addr;
   402 	float vec[3];
   403 	pContext->LocalToPhysAddr(params[2], &addr);
   404 
   405 	if (!g_CurrentTE->TE_GetEntDataVector(prop, vec))
   406 	{
   407 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   408 	}
   409 
   410 	addr[0] = sp_ftoc(vec[0]);
   411 	addr[1] = sp_ftoc(vec[1]);
   412 	addr[2] = sp_ftoc(vec[2]);
   413 
   414 	return 1;
   415 }
   416 
   417 static cell_t smn_TEWriteFloatArray(IPluginContext *pContext, const cell_t *params)
   418 {
   419 	if (!g_TEManager.IsAvailable())
   420 	{
   421 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   422 	}
   423 	if (!g_CurrentTE)
   424 	{
   425 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   426 	}
   427 
   428 	char *prop;
   429 	pContext->LocalToString(params[1], &prop);
   430 
   431 	cell_t *addr;
   432 	pContext->LocalToPhysAddr(params[2], &addr);
   433 
   434 	if (!g_CurrentTE->TE_SetEntDataFloatArray(prop, addr, params[3]))
   435 	{
   436 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   437 	}
   438 
   439 	return 1;
   440 }
   441 
   442 static cell_t smn_TESend(IPluginContext *pContext, const cell_t *params)
   443 {
   444 	if (!g_TEManager.IsAvailable())
   445 	{
   446 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   447 	}
   448 	if (!g_CurrentTE)
   449 	{
   450 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   451 	}
   452 
   453 	cell_t *cl_array;
   454 	unsigned int numClients;
   455 	int client;
   456 	IGamePlayer *pPlayer = NULL;
   457 
   458 	pContext->LocalToPhysAddr(params[1], &cl_array);
   459 	numClients = params[2];
   460 
   461 	/* Client validation */
   462 	for (unsigned int i = 0; i < numClients; i++)
   463 	{
   464 		client = cl_array[i];
   465 		pPlayer = playerhelpers->GetGamePlayer(client);
   466 
   467 		if (!pPlayer)
   468 		{
   469 			return pContext->ThrowNativeError("Client index %d is invalid", client);
   470 		} else if (!pPlayer->IsInGame()) {
   471 			return pContext->ThrowNativeError("Client %d is not connected", client);
   472 		}
   473 	}
   474 
   475 	g_TERecFilter.Reset();
   476 	g_TERecFilter.Initialize(cl_array, numClients);
   477 
   478 	g_CurrentTE->Send(g_TERecFilter, sp_ctof(params[3]));
   479 	g_CurrentTE = NULL;
   480 
   481 	return 1;
   482 }
   483 
   484 static cell_t smn_TEIsValidProp(IPluginContext *pContext, const cell_t *params)
   485 {
   486 	if (!g_TEManager.IsAvailable())
   487 	{
   488 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   489 	}
   490 	if (!g_CurrentTE)
   491 	{
   492 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   493 	}
   494 
   495 	char *prop;
   496 	pContext->LocalToString(params[1], &prop);
   497 
   498 	return g_CurrentTE->IsValidProp(prop) ? 1 : 0;
   499 }
   500 
   501 static cell_t smn_AddTempEntHook(IPluginContext *pContext, const cell_t *params)
   502 {
   503 	char *name;
   504 	IPluginFunction *pFunc;
   505 
   506 	if (!g_TEManager.IsAvailable())
   507 	{
   508 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   509 	}
   510 
   511 	pContext->LocalToString(params[1], &name);
   512 	pFunc = pContext->GetFunctionById(params[2]);
   513 	if (!pFunc)
   514 	{
   515 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   516 	}
   517 
   518 	if (!s_TempEntHooks.AddHook(name, pFunc))
   519 	{
   520 		return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
   521 	}
   522 
   523 	return 1;
   524 }
   525 
   526 static cell_t smn_RemoveTempEntHook(IPluginContext *pContext, const cell_t *params)
   527 {
   528 	char *name;
   529 	IPluginFunction *pFunc;
   530 
   531 	if (!g_TEManager.IsAvailable())
   532 	{
   533 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   534 	}
   535 
   536 	pContext->LocalToString(params[1], &name);
   537 	pFunc = pContext->GetFunctionById(params[2]);
   538 	if (!pFunc)
   539 	{
   540 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   541 	}
   542 
   543 	if (!s_TempEntHooks.RemoveHook(name, pFunc))
   544 	{
   545 		return pContext->ThrowNativeError("Invalid hooked TempEntity name or function");
   546 	}
   547 
   548 	return 1;
   549 }
   550 
   551 sp_nativeinfo_t g_TENatives[] = 
   552 {
   553 	{"TE_Start",				smn_TEStart},
   554 	{"TE_WriteNum",				smn_TEWriteNum},
   555 	{"TE_ReadNum",				smn_TEReadNum},
   556 	{"TE_WriteFloat",			smn_TE_WriteFloat},
   557 	{"TE_ReadFloat",			smn_TE_ReadFloat},
   558 	{"TE_WriteVector",			smn_TEWriteVector},
   559 	{"TE_ReadVector",			smn_TEReadVector},
   560 	{"TE_WriteAngles",			smn_TEWriteVector},
   561 	{"TE_Send",					smn_TESend},
   562 	{"TE_IsValidProp",			smn_TEIsValidProp},
   563 	{"TE_WriteFloatArray",		smn_TEWriteFloatArray},
   564 	{"AddTempEntHook",			smn_AddTempEntHook},
   565 	{"RemoveTempEntHook",		smn_RemoveTempEntHook},
   566 	{NULL,						NULL}
   567 };