extensions/sdktools/tenatives.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sun May 04 15:52:34 2008 +0000 (2008-05-04)
changeset 2038 a317edffcfa7
parent 1952 b7aa2b626807
child 2112 2a83a521287c
permissions -rw-r--r--
removed these functions in tf2 for now to avoid more crashes
     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[256];
    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_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, this, &TempEntHooks::OnPlaybackTempEntity, false);
   124 	}
   125 }
   126 
   127 void TempEntHooks::_DecRefCounter()
   128 {
   129 	if (--m_HookCount == 0)
   130 	{
   131 		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, 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 		pl_array[i] = pFilter->GetRecipientIndex(i);
   142 	}
   143 
   144 	return size;
   145 }
   146 
   147 bool TempEntHooks::AddHook(const char *name, IPluginFunction *pFunc)
   148 {
   149 	TEHookInfo *pInfo;
   150 
   151 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   152 	{
   153 		pInfo->lst.push_back(pFunc);
   154 	} else {
   155 		TempEntityInfo *te;
   156 		if (!(te=g_TEManager.GetTempEntityInfo(name)))
   157 		{
   158 			return false;
   159 		}
   160 
   161 		pInfo = new TEHookInfo;
   162 		pInfo->te = te;
   163 		pInfo->lst.push_back(pFunc);
   164 
   165 		m_TEHooks->Insert(name, reinterpret_cast<void *>(pInfo));
   166 		m_HookInfo.push_back(pInfo);
   167 	}
   168 
   169 	_IncRefCounter();
   170 
   171 	return true;
   172 }
   173 
   174 bool TempEntHooks::RemoveHook(const char *name, IPluginFunction *pFunc)
   175 {
   176 	TEHookInfo *pInfo;
   177 
   178 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   179 	{
   180 		SourceHook::List<IPluginFunction *>::iterator iter;
   181 		if ((iter=pInfo->lst.find(pFunc)) != pInfo->lst.end())
   182 		{
   183 			pInfo->lst.erase(iter);
   184 			if (pInfo->lst.empty())
   185 			{
   186 				m_HookInfo.remove(pInfo);
   187 				m_TEHooks->Delete(name);
   188 				delete pInfo;
   189 			}
   190 			_DecRefCounter();
   191 		} else {
   192 			return false;
   193 		}
   194 	} else {
   195 		return false;
   196 	}
   197 
   198 	return true;
   199 }
   200 
   201 void TempEntHooks::OnPlaybackTempEntity(IRecipientFilter &filter, float delay, const void *pSender, const SendTable *pST, int classID)
   202 {
   203 	TEHookInfo *pInfo;
   204 	const char *name = g_TEManager.GetNameFromThisPtr(const_cast<void *>(pSender));
   205 
   206 	if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
   207 	{
   208 		SourceHook::List<IPluginFunction *>::iterator iter;
   209 		IPluginFunction *pFunc;
   210 		size_t size;
   211 		cell_t res = static_cast<ResultType>(Pl_Continue);
   212 
   213 		TempEntityInfo *oldinfo = g_CurrentTE;
   214 		g_CurrentTE = pInfo->te;
   215 		size = _FillInPlayers(g_TEPlayers, &filter);
   216 
   217 		for (iter=pInfo->lst.begin(); iter!=pInfo->lst.end(); iter++)
   218 		{
   219 			pFunc = (*iter);
   220 			pFunc->PushString(name);
   221 			pFunc->PushArray(g_TEPlayers, size);
   222 			pFunc->PushCell(size);
   223 			pFunc->PushFloat(delay);
   224 			pFunc->Execute(&res);
   225 
   226 			if (res != Pl_Continue)
   227 			{
   228 				g_CurrentTE = oldinfo;
   229 				RETURN_META(MRES_SUPERCEDE);
   230 			}
   231 		}
   232 
   233 		g_CurrentTE = oldinfo;
   234 		RETURN_META(MRES_IGNORED);
   235 	}
   236 }
   237 
   238 /**********************
   239 *                     *
   240 * Temp Entity Natives *
   241 *                     *
   242 ***********************/
   243 
   244 TempEntHooks s_TempEntHooks;
   245 
   246 static cell_t smn_TEStart(IPluginContext *pContext, const cell_t *params)
   247 {
   248 	if (!g_TEManager.IsAvailable())
   249 	{
   250 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   251 	}
   252 
   253 	char *name;
   254 	pContext->LocalToString(params[1], &name);
   255 
   256 	g_CurrentTE = g_TEManager.GetTempEntityInfo(name);
   257 	if (!g_CurrentTE)
   258 	{
   259 		return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
   260 	}
   261 
   262 	return 1;
   263 }
   264 
   265 static cell_t smn_TEWriteNum(IPluginContext *pContext, const cell_t *params)
   266 {
   267 	if (!g_TEManager.IsAvailable())
   268 	{
   269 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   270 	}
   271 	if (!g_CurrentTE)
   272 	{
   273 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   274 	}
   275 
   276 	char *prop;
   277 	pContext->LocalToString(params[1], &prop);
   278 
   279 	if (!g_CurrentTE->TE_SetEntData(prop, params[2]))
   280 	{
   281 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   282 	}
   283 
   284 	return 1;
   285 }
   286 
   287 static cell_t smn_TEReadNum(IPluginContext *pContext, const cell_t *params)
   288 {
   289 	if (!g_TEManager.IsAvailable())
   290 	{
   291 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   292 	}
   293 	if (!g_CurrentTE)
   294 	{
   295 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   296 	}
   297 
   298 	char *prop;
   299 	int val;
   300 	pContext->LocalToString(params[1], &prop);
   301 
   302 	if (!g_CurrentTE->TE_GetEntData(prop, &val))
   303 	{
   304 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   305 	}
   306 
   307 	return val;
   308 }
   309 
   310 static cell_t smn_TE_WriteFloat(IPluginContext *pContext, const cell_t *params)
   311 {
   312 	if (!g_TEManager.IsAvailable())
   313 	{
   314 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   315 	}
   316 	if (!g_CurrentTE)
   317 	{
   318 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   319 	}
   320 
   321 	char *prop;
   322 	pContext->LocalToString(params[1], &prop);
   323 
   324 	if (!g_CurrentTE->TE_SetEntDataFloat(prop, sp_ctof(params[2])))
   325 	{
   326 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   327 	}
   328 
   329 	return 1;
   330 }
   331 
   332 static cell_t smn_TE_ReadFloat(IPluginContext *pContext, const cell_t *params)
   333 {
   334 	if (!g_TEManager.IsAvailable())
   335 	{
   336 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   337 	}
   338 	if (!g_CurrentTE)
   339 	{
   340 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   341 	}
   342 
   343 	char *prop;
   344 	float val;
   345 	pContext->LocalToString(params[1], &prop);
   346 
   347 	if (!g_CurrentTE->TE_GetEntDataFloat(prop, &val))
   348 	{
   349 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   350 	}
   351 
   352 	return sp_ftoc(val);
   353 }
   354 
   355 static cell_t smn_TEWriteVector(IPluginContext *pContext, const cell_t *params)
   356 {
   357 	if (!g_TEManager.IsAvailable())
   358 	{
   359 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   360 	}
   361 	if (!g_CurrentTE)
   362 	{
   363 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   364 	}
   365 
   366 	char *prop;
   367 	pContext->LocalToString(params[1], &prop);
   368 
   369 	cell_t *addr;
   370 	pContext->LocalToPhysAddr(params[2], &addr);
   371 	float vec[3] = {sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2])};
   372 
   373 	if (!g_CurrentTE->TE_SetEntDataVector(prop, vec))
   374 	{
   375 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   376 	}
   377 
   378 	return 1;
   379 }
   380 
   381 static cell_t smn_TEReadVector(IPluginContext *pContext, const cell_t *params)
   382 {
   383 	if (!g_TEManager.IsAvailable())
   384 	{
   385 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   386 	}
   387 	if (!g_CurrentTE)
   388 	{
   389 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   390 	}
   391 
   392 	char *prop;
   393 	pContext->LocalToString(params[1], &prop);
   394 
   395 	cell_t *addr;
   396 	float vec[3];
   397 	pContext->LocalToPhysAddr(params[2], &addr);
   398 
   399 	if (!g_CurrentTE->TE_GetEntDataVector(prop, vec))
   400 	{
   401 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   402 	}
   403 
   404 	addr[0] = sp_ftoc(vec[0]);
   405 	addr[1] = sp_ftoc(vec[1]);
   406 	addr[2] = sp_ftoc(vec[2]);
   407 
   408 	return 1;
   409 }
   410 
   411 static cell_t smn_TEWriteFloatArray(IPluginContext *pContext, const cell_t *params)
   412 {
   413 	if (!g_TEManager.IsAvailable())
   414 	{
   415 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   416 	}
   417 	if (!g_CurrentTE)
   418 	{
   419 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   420 	}
   421 
   422 	char *prop;
   423 	pContext->LocalToString(params[1], &prop);
   424 
   425 	cell_t *addr;
   426 	pContext->LocalToPhysAddr(params[2], &addr);
   427 
   428 	if (!g_CurrentTE->TE_SetEntDataFloatArray(prop, addr, params[3]))
   429 	{
   430 		return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
   431 	}
   432 
   433 	return 1;
   434 }
   435 
   436 static cell_t smn_TESend(IPluginContext *pContext, const cell_t *params)
   437 {
   438 	if (!g_TEManager.IsAvailable())
   439 	{
   440 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   441 	}
   442 	if (!g_CurrentTE)
   443 	{
   444 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   445 	}
   446 
   447 	cell_t *cl_array;
   448 	pContext->LocalToPhysAddr(params[1], &cl_array);
   449 
   450 	g_TERecFilter.Reset();
   451 	g_TERecFilter.Initialize(cl_array, params[2]);
   452 
   453 	g_CurrentTE->Send(g_TERecFilter, sp_ctof(params[3]));
   454 	g_CurrentTE = NULL;
   455 
   456 	return 1;
   457 }
   458 
   459 static cell_t smn_TEIsValidProp(IPluginContext *pContext, const cell_t *params)
   460 {
   461 	if (!g_TEManager.IsAvailable())
   462 	{
   463 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   464 	}
   465 	if (!g_CurrentTE)
   466 	{
   467 		return pContext->ThrowNativeError("No TempEntity call is in progress");
   468 	}
   469 
   470 	char *prop;
   471 	pContext->LocalToString(params[1], &prop);
   472 
   473 	return g_CurrentTE->IsValidProp(prop) ? 1 : 0;
   474 }
   475 
   476 static cell_t smn_AddTempEntHook(IPluginContext *pContext, const cell_t *params)
   477 {
   478 	char *name;
   479 	IPluginFunction *pFunc;
   480 
   481 	if (!g_TEManager.IsAvailable())
   482 	{
   483 		return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
   484 	}
   485 
   486 	pContext->LocalToString(params[1], &name);
   487 	pFunc = pContext->GetFunctionById(params[2]);
   488 	if (!pFunc)
   489 	{
   490 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   491 	}
   492 
   493 	if (!s_TempEntHooks.AddHook(name, pFunc))
   494 	{
   495 		return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
   496 	}
   497 
   498 	return 1;
   499 }
   500 
   501 static cell_t smn_RemoveTempEntHook(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.RemoveHook(name, pFunc))
   519 	{
   520 		return pContext->ThrowNativeError("Invalid hooked TempEntity name or function");
   521 	}
   522 
   523 	return 1;
   524 }
   525 
   526 sp_nativeinfo_t g_TENatives[] = 
   527 {
   528 	{"TE_Start",				smn_TEStart},
   529 	{"TE_WriteNum",				smn_TEWriteNum},
   530 	{"TE_ReadNum",				smn_TEReadNum},
   531 	{"TE_WriteFloat",			smn_TE_WriteFloat},
   532 	{"TE_ReadFloat",			smn_TE_ReadFloat},
   533 	{"TE_WriteVector",			smn_TEWriteVector},
   534 	{"TE_ReadVector",			smn_TEReadVector},
   535 	{"TE_WriteAngles",			smn_TEWriteVector},
   536 	{"TE_Send",					smn_TESend},
   537 	{"TE_IsValidProp",			smn_TEIsValidProp},
   538 	{"TE_WriteFloatArray",		smn_TEWriteFloatArray},
   539 	{"AddTempEntHook",			smn_AddTempEntHook},
   540 	{"RemoveTempEntHook",		smn_RemoveTempEntHook},
   541 	{NULL,						NULL}
   542 };