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