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: };