pred@1958: /** pred@1958: * vim: set ts=4 : pred@1958: * ============================================================================= pred@1958: * SourceMod SDKTools Extension ds@1990: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. pred@1958: * ============================================================================= pred@1958: * pred@1958: * This program is free software; you can redistribute it and/or modify it under pred@1958: * the terms of the GNU General Public License, version 3.0, as published by the pred@1958: * Free Software Foundation. pred@1958: * pred@1958: * This program is distributed in the hope that it will be useful, but WITHOUT pred@1958: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS pred@1958: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more pred@1958: * details. pred@1958: * pred@1958: * You should have received a copy of the GNU General Public License along with pred@1958: * this program. If not, see . pred@1958: * pred@1958: * As a special exception, AlliedModders LLC gives you permission to link the pred@1958: * code of this program (as well as its derivative works) to "Half-Life 2," the pred@1958: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software pred@1958: * by the Valve Corporation. You must obey the GNU General Public License in pred@1958: * all respects for all other code used. Additionally, AlliedModders LLC grants pred@1958: * this exception to all derivative works. AlliedModders LLC defines further pred@1958: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), pred@1958: * or . pred@1958: * ds@1987: * Version: $Id$ pred@1958: */ pred@1958: pred@1958: #include "extension.h" pred@1958: #include "output.h" pred@1958: pred@1958: // HookSingleEntityOutput(ent, const String:output[], function, bool:once); pred@1958: cell_t HookSingleEntityOutput(IPluginContext *pContext, const cell_t *params) pred@1958: { pred@1958: if (!g_OutputManager.IsEnabled()) pred@1958: { pred@1958: return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); pred@1958: } pred@1958: pred@2746: CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]); pred@2746: if (!pEntity) pred@1958: { pred@2746: return pContext->ThrowNativeError("Invalid Entity index %i (%i)", gamehelpers->ReferenceToIndex(params[1]), params[1]); pred@1958: } pred@2746: pred@2746: const char *classname = g_OutputManager.GetEntityClassname(pEntity); pred@1958: pred@1958: char *outputname; pred@1958: pContext->LocalToString(params[2], &outputname); pred@1958: pred@1958: OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true); pred@1958: pred@1958: //Check for an existing identical hook pred@1958: SourceHook::List::iterator _iter; pred@1958: pred@1958: omg_hooks *hook; pred@1958: pred@1958: IPluginFunction *pFunction; pred@1958: pFunction = pContext->GetFunctionById(params[3]); pred@1958: pred@1958: for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) pred@1958: { pred@1958: hook = (omg_hooks *)*_iter; pred@2746: if (hook->pf == pFunction && hook->entity_ref == gamehelpers->EntityToReference(pEntity)) pred@1958: { pred@1958: return 0; pred@1958: } pred@1958: } pred@1958: pred@1958: hook = g_OutputManager.NewHook(); pred@1958: pred@2746: hook->entity_ref = gamehelpers->EntityToReference(pEntity); pred@1958: hook->only_once= !!params[4]; pred@1958: hook->pf = pFunction; pred@1958: hook->m_parent = pOutputName; pred@1958: hook->in_use = false; pred@1958: hook->delete_me = false; pred@1958: pred@1958: pOutputName->hooks.push_back(hook); pred@1958: pred@1958: g_OutputManager.OnHookAdded(); pred@1958: pred@1958: IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); pred@1958: SourceHook::List *pList = NULL; pred@1958: pred@1958: if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList) pred@1958: { pred@1958: pList = new SourceHook::List; pred@1958: pPlugin->SetProperty("OutputHookList", pList); pred@1958: } pred@1958: pred@1958: pList->push_back(hook); pred@1958: pred@1958: return 1; pred@1958: } pred@1958: pred@1958: // HookEntityOutput(const String:classname[], const String:output[], function); pred@1958: cell_t HookEntityOutput(IPluginContext *pContext, const cell_t *params) pred@1958: { pred@1958: if (!g_OutputManager.IsEnabled()) pred@1958: { pred@1958: return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); pred@1958: } pred@1958: pred@1958: //Find or create the base structures for this classname and the output pred@1958: char *classname; pred@1958: pContext->LocalToString(params[1], &classname); pred@1958: pred@1958: char *outputname; pred@1958: pContext->LocalToString(params[2], &outputname); pred@1958: pred@1958: OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, true); pred@1958: pred@1958: //Check for an existing identical hook pred@1958: SourceHook::List::iterator _iter; pred@1958: pred@1958: omg_hooks *hook; pred@1958: pred@1958: IPluginFunction *pFunction; pred@1958: pFunction = pContext->GetFunctionById(params[3]); pred@1958: pred@1958: for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) pred@1958: { pred@1958: hook = (omg_hooks *)*_iter; pred@2746: if (hook->pf == pFunction && hook->entity_ref == -1) pred@1958: { pred@1958: //already hooked to this function... pred@1958: //throw an error or just let them get away with stupidity? pred@1958: // seems like poor coding if they dont know if something is hooked or not pred@1958: return 0; pred@1958: } pred@1958: } pred@1958: pred@1958: hook = g_OutputManager.NewHook(); pred@1958: pred@2746: hook->entity_ref = -1; pred@1958: hook->pf = pFunction; pred@1958: hook->m_parent = pOutputName; pred@1958: hook->in_use = false; pred@1958: hook->delete_me = false; pred@1958: pred@1958: pOutputName->hooks.push_back(hook); pred@1958: pred@1958: g_OutputManager.OnHookAdded(); pred@1958: pred@1958: IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); pred@1958: SourceHook::List *pList = NULL; pred@1958: pred@1958: if (!pPlugin->GetProperty("OutputHookList", (void **)&pList, false) || !pList) pred@1958: { pred@1958: pList = new SourceHook::List; pred@1958: pPlugin->SetProperty("OutputHookList", pList); pred@1958: } pred@1958: pred@1958: pList->push_back(hook); pred@1958: pred@1958: return 1; pred@1958: } pred@1958: pred@1958: // UnHookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback); pred@1958: cell_t UnHookEntityOutput(IPluginContext *pContext, const cell_t *params) pred@1958: { pred@1958: if (!g_OutputManager.IsEnabled()) pred@1958: { pred@1958: return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); pred@1958: } pred@1958: pred@1958: char *classname; pred@1958: pContext->LocalToString(params[1], &classname); pred@1958: pred@1958: char *outputname; pred@1958: pContext->LocalToString(params[2], &outputname); pred@1958: pred@1958: OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false); pred@1958: pred@1958: if (!pOutputName) pred@1958: { pred@1958: return 0; pred@1958: } pred@1958: pred@1958: //Check for an existing identical hook pred@1958: SourceHook::List::iterator _iter; pred@1958: pred@1958: omg_hooks *hook; pred@1958: pred@1958: IPluginFunction *pFunction; pred@1958: pFunction = pContext->GetFunctionById(params[3]); pred@1958: pred@1958: for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) pred@1958: { pred@1958: hook = (omg_hooks *)*_iter; pred@2746: if (hook->pf == pFunction && hook->entity_ref == -1) pred@1958: { pred@1958: // remove this hook. pred@1958: if (hook->in_use) pred@1958: { pred@1958: hook->delete_me = true; pred@1958: return 1; pred@1958: } pred@1958: pred@1958: pOutputName->hooks.erase(_iter); pred@1958: g_OutputManager.CleanUpHook(hook); pred@1958: pred@1958: return 1; pred@1958: } pred@1958: } pred@1958: pred@1958: return 0; pred@1958: } pred@1958: pred@1958: // UnHookSingleEntityOutput(entity, const String:output[], EntityOutput:callback); pred@1958: cell_t UnHookSingleEntityOutput(IPluginContext *pContext, const cell_t *params) pred@1958: { pred@1958: if (!g_OutputManager.IsEnabled()) pred@1958: { pred@1958: return pContext->ThrowNativeError("Entity Outputs are disabled - See error logs for details"); pred@1958: } pred@1958: pred@1958: // Find the classname of the entity and lookup the classname and output structures pred@2746: CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]); pred@2746: if (!pEntity) pred@1958: { pred@2746: return pContext->ThrowNativeError("Invalid Entity index %i (%i)", gamehelpers->ReferenceToIndex(params[1]), params[1]); pred@1958: } pred@1958: pred@2746: const char *classname = g_OutputManager.GetEntityClassname(pEntity); pred@1958: pred@1958: char *outputname; pred@1958: pContext->LocalToString(params[2], &outputname); pred@1958: pred@1958: OutputNameStruct *pOutputName = g_OutputManager.FindOutputPointer((const char *)classname, outputname, false); pred@1958: pred@1958: if (!pOutputName) pred@1958: { pred@1958: return 0; pred@1958: } pred@1958: pred@1958: //Check for an existing identical hook pred@1958: SourceHook::List::iterator _iter; pred@1958: pred@1958: omg_hooks *hook; pred@1958: pred@1958: IPluginFunction *pFunction; pred@1958: pFunction = pContext->GetFunctionById(params[3]); pred@1958: pred@1958: for (_iter=pOutputName->hooks.begin(); _iter!=pOutputName->hooks.end(); _iter++) pred@1958: { pred@1958: hook = (omg_hooks *)*_iter; pred@2746: /* We're not serial checking and just removing by index here - This was always allowed so is left for bcompat */ pred@2746: if (hook->pf == pFunction && gamehelpers->ReferenceToIndex(hook->entity_ref) == gamehelpers->ReferenceToIndex(params[1])) pred@1958: { pred@1958: // remove this hook. pred@1958: if (hook->in_use) pred@1958: { pred@1958: hook->delete_me = true; pred@1958: return 1; pred@1958: } pred@1958: pred@1958: pOutputName->hooks.erase(_iter); pred@1958: g_OutputManager.CleanUpHook(hook); pred@1958: pred@1958: return 1; pred@1958: } pred@1958: } pred@1958: pred@1958: return 0; pred@1958: } pred@1958: pred@1958: sp_nativeinfo_t g_EntOutputNatives[] = pred@1958: { pred@1958: {"HookEntityOutput", HookEntityOutput}, pred@1960: {"UnhookEntityOutput", UnHookEntityOutput}, pred@1958: {"HookSingleEntityOutput", HookSingleEntityOutput}, pred@1960: {"UnhookSingleEntityOutput", UnHookSingleEntityOutput}, pred@1958: {NULL, NULL}, pred@2028: };