3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
33 #include "CellRecipientFilter.h"
34 #include <IForwardSys.h>
36 SH_DECL_HOOK5_void(IVEngineServer, PlaybackTempEntity, SH_NOATTRIB, 0, IRecipientFilter &, float, const void *, const SendTable *, int);
38 CellRecipientFilter g_TERecFilter;
39 TempEntityInfo *g_CurrentTE = NULL;
41 bool tenatives_initialized = false;
43 /*************************
45 * Temp Entity Hook Class *
47 **************************/
49 void TempEntHooks::Initialize()
51 m_TEHooks = adtfactory->CreateBasicTrie();
52 plsys->AddPluginsListener(this);
53 tenatives_initialized = true;
56 void TempEntHooks::Shutdown()
58 if (!tenatives_initialized)
63 plsys->RemovePluginsListener(this);
64 SourceHook::List<TEHookInfo *>::iterator iter;
65 for (iter=m_HookInfo.begin(); iter!=m_HookInfo.end(); iter++)
75 tenatives_initialized = false;
78 void TempEntHooks::OnPluginUnloaded(IPlugin *plugin)
80 SourceHook::List<TEHookInfo *>::iterator iter = m_HookInfo.begin();
81 IPluginContext *pContext = plugin->GetBaseContext();
83 /* For each hook list... */
84 while (iter != m_HookInfo.end())
86 SourceHook::List<IPluginFunction *>::iterator f_iter = (*iter)->lst.begin();
88 /* Find the hooks on the given temp entity */
89 while (f_iter != (*iter)->lst.end())
91 /* If it matches, remove it and dec the ref count */
92 if ((*f_iter)->GetParentContext() == pContext)
94 f_iter = (*iter)->lst.erase(f_iter);
103 /* If there are no more hooks left, we can safely
104 * remove it from the cache and remove its list.
106 if ((*iter)->lst.size() == 0)
108 m_TEHooks->Delete((*iter)->te->GetName());
110 iter = m_HookInfo.erase(iter);
119 void TempEntHooks::_IncRefCounter()
121 if (m_HookCount++ == 0)
123 SH_ADD_HOOK_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, this, &TempEntHooks::OnPlaybackTempEntity, false);
127 void TempEntHooks::_DecRefCounter()
129 if (--m_HookCount == 0)
131 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, this, &TempEntHooks::OnPlaybackTempEntity, false);
135 size_t TempEntHooks::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
137 size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
139 for (size_t i=0; i<size; i++)
141 pl_array[i] = pFilter->GetRecipientIndex(i);
147 bool TempEntHooks::AddHook(const char *name, IPluginFunction *pFunc)
151 if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
153 pInfo->lst.push_back(pFunc);
156 if (!(te=g_TEManager.GetTempEntityInfo(name)))
161 pInfo = new TEHookInfo;
163 pInfo->lst.push_back(pFunc);
165 m_TEHooks->Insert(name, reinterpret_cast<void *>(pInfo));
166 m_HookInfo.push_back(pInfo);
174 bool TempEntHooks::RemoveHook(const char *name, IPluginFunction *pFunc)
178 if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
180 SourceHook::List<IPluginFunction *>::iterator iter;
181 if ((iter=pInfo->lst.find(pFunc)) != pInfo->lst.end())
183 pInfo->lst.erase(iter);
184 if (pInfo->lst.empty())
186 m_HookInfo.remove(pInfo);
187 m_TEHooks->Delete(name);
201 void TempEntHooks::OnPlaybackTempEntity(IRecipientFilter &filter, float delay, const void *pSender, const SendTable *pST, int classID)
204 const char *name = g_TEManager.GetNameFromThisPtr(const_cast<void *>(pSender));
206 if (m_TEHooks->Retrieve(name, reinterpret_cast<void **>(&pInfo)))
208 SourceHook::List<IPluginFunction *>::iterator iter;
209 IPluginFunction *pFunc;
211 cell_t res = static_cast<ResultType>(Pl_Continue);
213 TempEntityInfo *oldinfo = g_CurrentTE;
214 g_CurrentTE = pInfo->te;
215 size = _FillInPlayers(g_TEPlayers, &filter);
217 for (iter=pInfo->lst.begin(); iter!=pInfo->lst.end(); iter++)
220 pFunc->PushString(name);
221 pFunc->PushArray(g_TEPlayers, size);
222 pFunc->PushCell(size);
223 pFunc->PushFloat(delay);
224 pFunc->Execute(&res);
226 if (res != Pl_Continue)
228 g_CurrentTE = oldinfo;
229 RETURN_META(MRES_SUPERCEDE);
233 g_CurrentTE = oldinfo;
234 RETURN_META(MRES_IGNORED);
238 /**********************
240 * Temp Entity Natives *
242 ***********************/
244 TempEntHooks s_TempEntHooks;
246 static cell_t smn_TEStart(IPluginContext *pContext, const cell_t *params)
248 if (!g_TEManager.IsAvailable())
250 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
254 pContext->LocalToString(params[1], &name);
256 g_CurrentTE = g_TEManager.GetTempEntityInfo(name);
259 return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
265 static cell_t smn_TEWriteNum(IPluginContext *pContext, const cell_t *params)
267 if (!g_TEManager.IsAvailable())
269 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
273 return pContext->ThrowNativeError("No TempEntity call is in progress");
277 pContext->LocalToString(params[1], &prop);
279 if (!g_CurrentTE->TE_SetEntData(prop, params[2]))
281 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
287 static cell_t smn_TEReadNum(IPluginContext *pContext, const cell_t *params)
289 if (!g_TEManager.IsAvailable())
291 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
295 return pContext->ThrowNativeError("No TempEntity call is in progress");
300 pContext->LocalToString(params[1], &prop);
302 if (!g_CurrentTE->TE_GetEntData(prop, &val))
304 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
310 static cell_t smn_TE_WriteFloat(IPluginContext *pContext, const cell_t *params)
312 if (!g_TEManager.IsAvailable())
314 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
318 return pContext->ThrowNativeError("No TempEntity call is in progress");
322 pContext->LocalToString(params[1], &prop);
324 if (!g_CurrentTE->TE_SetEntDataFloat(prop, sp_ctof(params[2])))
326 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
332 static cell_t smn_TE_ReadFloat(IPluginContext *pContext, const cell_t *params)
334 if (!g_TEManager.IsAvailable())
336 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
340 return pContext->ThrowNativeError("No TempEntity call is in progress");
345 pContext->LocalToString(params[1], &prop);
347 if (!g_CurrentTE->TE_GetEntDataFloat(prop, &val))
349 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
355 static cell_t smn_TEWriteVector(IPluginContext *pContext, const cell_t *params)
357 if (!g_TEManager.IsAvailable())
359 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
363 return pContext->ThrowNativeError("No TempEntity call is in progress");
367 pContext->LocalToString(params[1], &prop);
370 pContext->LocalToPhysAddr(params[2], &addr);
371 float vec[3] = {sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2])};
373 if (!g_CurrentTE->TE_SetEntDataVector(prop, vec))
375 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
381 static cell_t smn_TEReadVector(IPluginContext *pContext, const cell_t *params)
383 if (!g_TEManager.IsAvailable())
385 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
389 return pContext->ThrowNativeError("No TempEntity call is in progress");
393 pContext->LocalToString(params[1], &prop);
397 pContext->LocalToPhysAddr(params[2], &addr);
399 if (!g_CurrentTE->TE_GetEntDataVector(prop, vec))
401 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
404 addr[0] = sp_ftoc(vec[0]);
405 addr[1] = sp_ftoc(vec[1]);
406 addr[2] = sp_ftoc(vec[2]);
411 static cell_t smn_TEWriteFloatArray(IPluginContext *pContext, const cell_t *params)
413 if (!g_TEManager.IsAvailable())
415 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
419 return pContext->ThrowNativeError("No TempEntity call is in progress");
423 pContext->LocalToString(params[1], &prop);
426 pContext->LocalToPhysAddr(params[2], &addr);
428 if (!g_CurrentTE->TE_SetEntDataFloatArray(prop, addr, params[3]))
430 return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
436 static cell_t smn_TESend(IPluginContext *pContext, const cell_t *params)
438 if (!g_TEManager.IsAvailable())
440 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
444 return pContext->ThrowNativeError("No TempEntity call is in progress");
448 pContext->LocalToPhysAddr(params[1], &cl_array);
450 g_TERecFilter.Reset();
451 g_TERecFilter.Initialize(cl_array, params[2]);
453 g_CurrentTE->Send(g_TERecFilter, sp_ctof(params[3]));
459 static cell_t smn_TEIsValidProp(IPluginContext *pContext, const cell_t *params)
461 if (!g_TEManager.IsAvailable())
463 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
467 return pContext->ThrowNativeError("No TempEntity call is in progress");
471 pContext->LocalToString(params[1], &prop);
473 return g_CurrentTE->IsValidProp(prop) ? 1 : 0;
476 static cell_t smn_AddTempEntHook(IPluginContext *pContext, const cell_t *params)
479 IPluginFunction *pFunc;
481 if (!g_TEManager.IsAvailable())
483 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
486 pContext->LocalToString(params[1], &name);
487 pFunc = pContext->GetFunctionById(params[2]);
490 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
493 if (!s_TempEntHooks.AddHook(name, pFunc))
495 return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
501 static cell_t smn_RemoveTempEntHook(IPluginContext *pContext, const cell_t *params)
504 IPluginFunction *pFunc;
506 if (!g_TEManager.IsAvailable())
508 return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
511 pContext->LocalToString(params[1], &name);
512 pFunc = pContext->GetFunctionById(params[2]);
515 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
518 if (!s_TempEntHooks.RemoveHook(name, pFunc))
520 return pContext->ThrowNativeError("Invalid hooked TempEntity name or function");
526 sp_nativeinfo_t g_TENatives[] =
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},