diff -r 000000000000 -r c24a6fa957db extensions/sdktools/tenatives.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/sdktools/tenatives.cpp Sun Jul 06 04:49:55 2008 +0000
@@ -0,0 +1,561 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod SDKTools Extension
+ * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include "tempents.h"
+#include "CellRecipientFilter.h"
+#include
+
+SH_DECL_HOOK5_void(IVEngineServer, PlaybackTempEntity, SH_NOATTRIB, 0, IRecipientFilter &, float, const void *, const SendTable *, int);
+
+CellRecipientFilter g_TERecFilter;
+TempEntityInfo *g_CurrentTE = NULL;
+int g_TEPlayers[256];
+bool tenatives_initialized = false;
+
+/*************************
+* *
+* Temp Entity Hook Class *
+* *
+**************************/
+
+void TempEntHooks::Initialize()
+{
+ m_TEHooks = adtfactory->CreateBasicTrie();
+ plsys->AddPluginsListener(this);
+ tenatives_initialized = true;
+}
+
+void TempEntHooks::Shutdown()
+{
+ if (!tenatives_initialized)
+ {
+ return;
+ }
+
+ plsys->RemovePluginsListener(this);
+ SourceHook::List::iterator iter;
+ for (iter=m_HookInfo.begin(); iter!=m_HookInfo.end(); iter++)
+ {
+ delete (*iter);
+ }
+ if (m_HookCount)
+ {
+ m_HookCount = 1;
+ _DecRefCounter();
+ }
+ m_TEHooks->Destroy();
+ tenatives_initialized = false;
+}
+
+void TempEntHooks::OnPluginUnloaded(IPlugin *plugin)
+{
+ SourceHook::List::iterator iter = m_HookInfo.begin();
+ IPluginContext *pContext = plugin->GetBaseContext();
+
+ /* For each hook list... */
+ while (iter != m_HookInfo.end())
+ {
+ SourceHook::List::iterator f_iter = (*iter)->lst.begin();
+
+ /* Find the hooks on the given temp entity */
+ while (f_iter != (*iter)->lst.end())
+ {
+ /* If it matches, remove it and dec the ref count */
+ if ((*f_iter)->GetParentContext() == pContext)
+ {
+ f_iter = (*iter)->lst.erase(f_iter);
+ _DecRefCounter();
+ }
+ else
+ {
+ f_iter++;
+ }
+ }
+
+ /* If there are no more hooks left, we can safely
+ * remove it from the cache and remove its list.
+ */
+ if ((*iter)->lst.size() == 0)
+ {
+ m_TEHooks->Delete((*iter)->te->GetName());
+ delete (*iter);
+ iter = m_HookInfo.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+}
+
+void TempEntHooks::_IncRefCounter()
+{
+ if (m_HookCount++ == 0)
+ {
+ SH_ADD_HOOK_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, this, &TempEntHooks::OnPlaybackTempEntity, false);
+ }
+}
+
+void TempEntHooks::_DecRefCounter()
+{
+ if (--m_HookCount == 0)
+ {
+ SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, PlaybackTempEntity, engine, this, &TempEntHooks::OnPlaybackTempEntity, false);
+ }
+}
+
+size_t TempEntHooks::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
+{
+ size_t size = static_cast(pFilter->GetRecipientCount());
+
+ for (size_t i=0; iGetRecipientIndex(i);
+ }
+
+ return size;
+}
+
+bool TempEntHooks::AddHook(const char *name, IPluginFunction *pFunc)
+{
+ TEHookInfo *pInfo;
+
+ if (m_TEHooks->Retrieve(name, reinterpret_cast(&pInfo)))
+ {
+ pInfo->lst.push_back(pFunc);
+ } else {
+ TempEntityInfo *te;
+ if (!(te=g_TEManager.GetTempEntityInfo(name)))
+ {
+ return false;
+ }
+
+ pInfo = new TEHookInfo;
+ pInfo->te = te;
+ pInfo->lst.push_back(pFunc);
+
+ m_TEHooks->Insert(name, reinterpret_cast(pInfo));
+ m_HookInfo.push_back(pInfo);
+ }
+
+ _IncRefCounter();
+
+ return true;
+}
+
+bool TempEntHooks::RemoveHook(const char *name, IPluginFunction *pFunc)
+{
+ TEHookInfo *pInfo;
+
+ if (m_TEHooks->Retrieve(name, reinterpret_cast(&pInfo)))
+ {
+ SourceHook::List::iterator iter;
+ if ((iter=pInfo->lst.find(pFunc)) != pInfo->lst.end())
+ {
+ pInfo->lst.erase(iter);
+ if (pInfo->lst.empty())
+ {
+ m_HookInfo.remove(pInfo);
+ m_TEHooks->Delete(name);
+ delete pInfo;
+ }
+ _DecRefCounter();
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void TempEntHooks::OnPlaybackTempEntity(IRecipientFilter &filter, float delay, const void *pSender, const SendTable *pST, int classID)
+{
+ TEHookInfo *pInfo;
+ const char *name = g_TEManager.GetNameFromThisPtr(const_cast(pSender));
+
+ if (m_TEHooks->Retrieve(name, reinterpret_cast(&pInfo)))
+ {
+ SourceHook::List::iterator iter;
+ IPluginFunction *pFunc;
+ size_t size;
+ cell_t res = static_cast(Pl_Continue);
+
+ TempEntityInfo *oldinfo = g_CurrentTE;
+ g_CurrentTE = pInfo->te;
+ size = _FillInPlayers(g_TEPlayers, &filter);
+
+ for (iter=pInfo->lst.begin(); iter!=pInfo->lst.end(); iter++)
+ {
+ pFunc = (*iter);
+ pFunc->PushString(name);
+ pFunc->PushArray(g_TEPlayers, size);
+ pFunc->PushCell(size);
+ pFunc->PushFloat(delay);
+ pFunc->Execute(&res);
+
+ if (res != Pl_Continue)
+ {
+ g_CurrentTE = oldinfo;
+ RETURN_META(MRES_SUPERCEDE);
+ }
+ }
+
+ g_CurrentTE = oldinfo;
+ RETURN_META(MRES_IGNORED);
+ }
+}
+
+/**********************
+* *
+* Temp Entity Natives *
+* *
+***********************/
+
+TempEntHooks s_TempEntHooks;
+
+static cell_t smn_TEStart(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+
+ char *name;
+ pContext->LocalToString(params[1], &name);
+
+ g_CurrentTE = g_TEManager.GetTempEntityInfo(name);
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
+ }
+
+ return 1;
+}
+
+static cell_t smn_TEWriteNum(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ if (!g_CurrentTE->TE_SetEntData(prop, params[2]))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return 1;
+}
+
+static cell_t smn_TEReadNum(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ int val;
+ pContext->LocalToString(params[1], &prop);
+
+ if (!g_CurrentTE->TE_GetEntData(prop, &val))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return val;
+}
+
+static cell_t smn_TE_WriteFloat(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ if (!g_CurrentTE->TE_SetEntDataFloat(prop, sp_ctof(params[2])))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return 1;
+}
+
+static cell_t smn_TE_ReadFloat(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ float val;
+ pContext->LocalToString(params[1], &prop);
+
+ if (!g_CurrentTE->TE_GetEntDataFloat(prop, &val))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return sp_ftoc(val);
+}
+
+static cell_t smn_TEWriteVector(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ cell_t *addr;
+ pContext->LocalToPhysAddr(params[2], &addr);
+ float vec[3] = {sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2])};
+
+ if (!g_CurrentTE->TE_SetEntDataVector(prop, vec))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return 1;
+}
+
+static cell_t smn_TEReadVector(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ cell_t *addr;
+ float vec[3];
+ pContext->LocalToPhysAddr(params[2], &addr);
+
+ if (!g_CurrentTE->TE_GetEntDataVector(prop, vec))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ addr[0] = sp_ftoc(vec[0]);
+ addr[1] = sp_ftoc(vec[1]);
+ addr[2] = sp_ftoc(vec[2]);
+
+ return 1;
+}
+
+static cell_t smn_TEWriteFloatArray(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ cell_t *addr;
+ pContext->LocalToPhysAddr(params[2], &addr);
+
+ if (!g_CurrentTE->TE_SetEntDataFloatArray(prop, addr, params[3]))
+ {
+ return pContext->ThrowNativeError("Temp entity property \"%s\" not found", prop);
+ }
+
+ return 1;
+}
+
+static cell_t smn_TESend(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ cell_t *cl_array;
+ unsigned int numClients;
+ int client;
+ IGamePlayer *pPlayer = NULL;
+
+ pContext->LocalToPhysAddr(params[1], &cl_array);
+ numClients = params[2];
+
+ /* Client validation */
+ for (unsigned int i = 0; i < numClients; i++)
+ {
+ client = cl_array[i];
+ pPlayer = playerhelpers->GetGamePlayer(client);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", client);
+ } else if (!pPlayer->IsInGame()) {
+ return pContext->ThrowNativeError("Client %d is not connected", client);
+ }
+ }
+
+ g_TERecFilter.Reset();
+ g_TERecFilter.Initialize(cl_array, numClients);
+
+ g_CurrentTE->Send(g_TERecFilter, sp_ctof(params[3]));
+ g_CurrentTE = NULL;
+
+ return 1;
+}
+
+static cell_t smn_TEIsValidProp(IPluginContext *pContext, const cell_t *params)
+{
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+ if (!g_CurrentTE)
+ {
+ return pContext->ThrowNativeError("No TempEntity call is in progress");
+ }
+
+ char *prop;
+ pContext->LocalToString(params[1], &prop);
+
+ return g_CurrentTE->IsValidProp(prop) ? 1 : 0;
+}
+
+static cell_t smn_AddTempEntHook(IPluginContext *pContext, const cell_t *params)
+{
+ char *name;
+ IPluginFunction *pFunc;
+
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+
+ pContext->LocalToString(params[1], &name);
+ pFunc = pContext->GetFunctionById(params[2]);
+ if (!pFunc)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ if (!s_TempEntHooks.AddHook(name, pFunc))
+ {
+ return pContext->ThrowNativeError("Invalid TempEntity name: \"%s\"", name);
+ }
+
+ return 1;
+}
+
+static cell_t smn_RemoveTempEntHook(IPluginContext *pContext, const cell_t *params)
+{
+ char *name;
+ IPluginFunction *pFunc;
+
+ if (!g_TEManager.IsAvailable())
+ {
+ return pContext->ThrowNativeError("TempEntity System unsupported or not available, file a bug report");
+ }
+
+ pContext->LocalToString(params[1], &name);
+ pFunc = pContext->GetFunctionById(params[2]);
+ if (!pFunc)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ if (!s_TempEntHooks.RemoveHook(name, pFunc))
+ {
+ return pContext->ThrowNativeError("Invalid hooked TempEntity name or function");
+ }
+
+ return 1;
+}
+
+sp_nativeinfo_t g_TENatives[] =
+{
+ {"TE_Start", smn_TEStart},
+ {"TE_WriteNum", smn_TEWriteNum},
+ {"TE_ReadNum", smn_TEReadNum},
+ {"TE_WriteFloat", smn_TE_WriteFloat},
+ {"TE_ReadFloat", smn_TE_ReadFloat},
+ {"TE_WriteVector", smn_TEWriteVector},
+ {"TE_ReadVector", smn_TEReadVector},
+ {"TE_WriteAngles", smn_TEWriteVector},
+ {"TE_Send", smn_TESend},
+ {"TE_IsValidProp", smn_TEIsValidProp},
+ {"TE_WriteFloatArray", smn_TEWriteFloatArray},
+ {"AddTempEntHook", smn_AddTempEntHook},
+ {"RemoveTempEntHook", smn_RemoveTempEntHook},
+ {NULL, NULL}
+};