From a827da64eb5bcde23e833f77f733ed2ee383daaa Mon Sep 17 00:00:00 2001 From: BotoX Date: Tue, 24 May 2016 19:56:06 +0200 Subject: [PATCH] added natives to delete outputs added native to find output refactored some code --- AMBuilder | 3 +- PackageScript | 8 +- extension.cpp | 331 +++++++++++++++++++++++++++++----------- extension.h | 4 +- gamedata/outputinfo.txt | 14 ++ include/outputinfo.inc | 20 ++- smsdk_config.h | 4 +- 7 files changed, 289 insertions(+), 95 deletions(-) create mode 100644 gamedata/outputinfo.txt diff --git a/AMBuilder b/AMBuilder index da57cd9..df34490 100644 --- a/AMBuilder +++ b/AMBuilder @@ -18,7 +18,8 @@ for sdk_name in SM.sdks: binary = SM.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk) binary.compiler.cxxincludes += [ os.path.join(sdk.path, 'game', 'server'), - os.path.join(SM.sm_root, 'public', 'sourcepawn') + os.path.join(SM.sm_root, 'public', 'sourcepawn'), + os.path.join(SM.sm_root, 'public', 'amtl') ] SM.extensions += builder.Add(project) diff --git a/PackageScript b/PackageScript index 1eeafd3..f9315d9 100644 --- a/PackageScript +++ b/PackageScript @@ -9,6 +9,7 @@ builder.SetBuildFolder('package') folder_list = [ 'addons/sourcemod/extensions', 'addons/sourcemod/scripting/include', + 'addons/sourcemod/gamedata' ] # Create the distribution folder hierarchy. @@ -28,7 +29,12 @@ def CopyFiles(src, dest, files): # Include files CopyFiles('include', 'addons/sourcemod/scripting/include', - [ 'outputinfo.inc', ] + [ 'outputinfo.inc' ] +) + +# Gamedata +CopyFiles('gamedata', 'addons/sourcemod/gamedata', + [ 'outputinfo.txt' ] ) # Copy binaries. diff --git a/extension.cpp b/extension.cpp index 37e7ebf..25b8522 100644 --- a/extension.cpp +++ b/extension.cpp @@ -29,6 +29,7 @@ * Version: $Id$ */ +#include #include "extension.h" /** @@ -40,11 +41,11 @@ Outputinfo g_Outputinfo; /**< Global singleton for extension's main interface * SMEXT_LINK(&g_Outputinfo); +IGameConfig *g_pGameConf = NULL; + #include #include -#define EVENT_FIRE_ALWAYS -1 - class CEventAction { public: @@ -54,66 +55,108 @@ public: string_t m_iTargetInput; // the name of the action to fire string_t m_iParameter; // parameter to send, 0 if none float m_flDelay; // the number of seconds to wait before firing the action - int m_nTimesToFire; // The number of times to fire this event, or EVENT_FIRE_ALWAYS. + int m_nTimesToFire; // The number of times to fire this event, or EVENT_FIRE_ALWAYS (-1). int m_iIDStamp; // unique identifier stamp static int s_iNextIDStamp; CEventAction *m_pNext; -/* - // allocates memory from engine.MPool/g_EntityListPool - static void *operator new( size_t stAllocateBlock ); - static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); - static void operator delete( void *pMem ); - static void operator delete( void *pMem , int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); } -*/ DECLARE_SIMPLE_DATADESC(); + static void (*s_pOperatorDeleteFunc)(void *pMem); + static void operator delete(void *pMem); }; +void (*CEventAction::s_pOperatorDeleteFunc)(void *pMem); + +void CEventAction::operator delete(void *pMem) +{ + s_pOperatorDeleteFunc(pMem); +} class CBaseEntityOutput { -public: - - ~CBaseEntityOutput(); - - void ParseEventAction( const char *EventData ); - void AddEventAction( CEventAction *pEventAction ); - - int Save( ISave &save ); - int Restore( IRestore &restore, int elementCount ); - - int NumberOfElements( void ); - - float GetMaxDelay( void ); - - fieldtype_t ValueFieldType() { return m_Value.FieldType(); } - - void FireOutput( variant_t Value, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 ); -/* - /// Delete every single action in the action list. - void DeleteAllElements( void ) ; -*/ public: variant_t m_Value; CEventAction *m_ActionList; DECLARE_SIMPLE_DATADESC(); - CBaseEntityOutput() {} // this class cannot be created, only it's children - -private: - CBaseEntityOutput( CBaseEntityOutput& ); // protect from accidental copying + int NumberOfElements(void); + CEventAction *GetElement(int Index); + int DeleteElement(int Index); + int DeleteAllElements(void); }; int CBaseEntityOutput::NumberOfElements(void) { - int count = 0; - for (CEventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext) + int Count = 0; + for(CEventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext) + Count++; + + return Count; +} + +CEventAction *CBaseEntityOutput::GetElement(int Index) +{ + int Count = 0; + for(CEventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext) { - count++; + if(Count == Index) + return ev; + + Count++; } - return count; + + return NULL; +} + +int CBaseEntityOutput::DeleteElement(int Index) +{ + CEventAction *pPrevEvent = NULL; + CEventAction *pEvent = NULL; + + int Count = 0; + for(CEventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext) + { + if(Count == Index) + { + pEvent = ev; + break; + } + pPrevEvent = ev; + Count++; + } + + if(pEvent == NULL) + return 0; + + if(pPrevEvent != NULL) + pPrevEvent->m_pNext = pEvent->m_pNext; + else + m_ActionList = pEvent->m_pNext; + + delete pEvent; + return 1; +} + +int CBaseEntityOutput::DeleteAllElements(void) +{ + // walk front to back, deleting as we go. We needn't fix up pointers because + // EVERYTHING will die. + + int Count = 0; + CEventAction *pNext = m_ActionList; + // wipe out the head + m_ActionList = NULL; + while(pNext) + { + CEventAction *pStrikeThis = pNext; + pNext = pNext->m_pNext; + delete pStrikeThis; + Count++; + } + + return Count; } inline int GetDataMapOffset(CBaseEntity *pEnt, const char *pName) @@ -153,7 +196,7 @@ cell_t GetOutputCount(IPluginContext *pContext, const cell_t *params) CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); if(pEntityOutput == NULL) - return 0; + return -1; return pEntityOutput->NumberOfElements(); } @@ -169,20 +212,14 @@ cell_t GetOutputTarget(IPluginContext *pContext, const cell_t *params) if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) return 0; - CEventAction *pActionList = pEntityOutput->m_ActionList; - for(int i = 0; i < params[3]; i++) - { - if(pActionList->m_pNext == NULL) - return 0; + CEventAction *pAction = pEntityOutput->GetElement(params[3]); + if(!pAction) + return 0; - pActionList = pActionList->m_pNext; - } + size_t Length; + pContext->StringToLocalUTF8(params[4], params[5], pAction->m_iTarget.ToCStr(), &Length); - int Len = strlen(pActionList->m_iTarget.ToCStr()); - - pContext->StringToLocal(params[4], Len + 1, pActionList->m_iTarget.ToCStr()); - - return Len; + return Length; } cell_t GetOutputTargetInput(IPluginContext *pContext, const cell_t *params) @@ -193,23 +230,17 @@ cell_t GetOutputTargetInput(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); - if (pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) return 0; - CEventAction *pActionList = pEntityOutput->m_ActionList; - for(int i = 0; i < params[3]; i++) - { - if(pActionList->m_pNext == NULL) - return 0; + CEventAction *pAction = pEntityOutput->GetElement(params[3]); + if(!pAction) + return 0; - pActionList = pActionList->m_pNext; - } + size_t Length; + pContext->StringToLocalUTF8(params[4], params[5], pAction->m_iTargetInput.ToCStr(), &Length); - int Len = strlen(pActionList->m_iTargetInput.ToCStr()); - - pContext->StringToLocal(params[4], Len + 1, pActionList->m_iTargetInput.ToCStr()); - - return Len; + return Length; } cell_t GetOutputParameter(IPluginContext *pContext, const cell_t *params) @@ -220,23 +251,17 @@ cell_t GetOutputParameter(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); - if (pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) return 0; - CEventAction *pActionList = pEntityOutput->m_ActionList; - for(int i = 0; i < params[3]; i++) - { - if(pActionList->m_pNext == NULL) - return 0; + CEventAction *pAction = pEntityOutput->GetElement(params[3]); + if(!pAction) + return 0; - pActionList = pActionList->m_pNext; - } + size_t Length; + pContext->StringToLocalUTF8(params[4], params[5], pAction->m_iParameter.ToCStr(), &Length); - int Len = strlen(pActionList->m_iParameter.ToCStr()); - - pContext->StringToLocal(params[4], Len + 1, pActionList->m_iParameter.ToCStr()); - - return Len; + return Length; } cell_t GetOutputDelay(IPluginContext *pContext, const cell_t *params) @@ -247,19 +272,123 @@ cell_t GetOutputDelay(IPluginContext *pContext, const cell_t *params) CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); - if (pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) return -1; - CEventAction *pActionList = pEntityOutput->m_ActionList; - for(int i = 0; i < params[3]; i++) - { - if(pActionList->m_pNext == NULL) - return -1; + CEventAction *pAction = pEntityOutput->GetElement(params[3]); + if(!pAction) + return -1; - pActionList = pActionList->m_pNext; + return *(cell_t *)&pAction->m_flDelay; +} + +cell_t GetOutputFormatted(IPluginContext *pContext, const cell_t *params) +{ + char *pOutput; + pContext->LocalToString(params[2], &pOutput); + + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); + CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); + + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + return 0; + + CEventAction *pAction = pEntityOutput->GetElement(params[3]); + if(!pAction) + return 0; + + char aBuffer[1024]; + ke::SafeSprintf(aBuffer, sizeof(aBuffer), "%s,%s,%s,%g,%d", + pAction->m_iTarget.ToCStr(), + pAction->m_iTargetInput.ToCStr(), + pAction->m_iParameter.ToCStr(), + pAction->m_flDelay, + pAction->m_nTimesToFire); + + size_t Length; + pContext->StringToLocalUTF8(params[4], params[5], aBuffer, &Length); + + return Length; +} + +cell_t FindOutput(IPluginContext *pContext, const cell_t *params) +{ + char *pOutput; + pContext->LocalToString(params[2], &pOutput); + + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); + CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); + + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + return -1; + + char *piTarget; + pContext->LocalToStringNULL(params[4], &piTarget); + char *piTargetInput; + pContext->LocalToStringNULL(params[5], &piTargetInput); + char *piParameter; + pContext->LocalToStringNULL(params[6], &piParameter); + float flDelay = *(float *)¶ms[7]; + cell_t nTimesToFire = params[8]; + + int StartCount = params[3]; + int Count = 0; + for(CEventAction *ev = pEntityOutput->m_ActionList; ev != NULL; ev = ev->m_pNext) + { + Count++; + if(StartCount > 0) + { + StartCount--; + continue; + } + + if(piTarget != NULL && strcmp(ev->m_iTarget.ToCStr(), piTarget) != 0) + continue; + + if(piTargetInput != NULL && strcmp(ev->m_iTargetInput.ToCStr(), piTargetInput) != 0) + continue; + + if(piParameter != NULL && strcmp(ev->m_iParameter.ToCStr(), piParameter) != 0) + continue; + + if(flDelay >= 0 && flDelay != ev->m_flDelay) + continue; + + if(nTimesToFire != 0 && nTimesToFire != ev->m_nTimesToFire) + continue; + + return Count - 1; } - return *(cell_t *)&pActionList->m_flDelay; + return -1; +} + +cell_t DeleteOutput(IPluginContext *pContext, const cell_t *params) +{ + char *pOutput; + pContext->LocalToString(params[2], &pOutput); + + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); + CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); + + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + return -1; + + return pEntityOutput->DeleteElement(params[3]); +} + +cell_t DeleteAllOutputs(IPluginContext *pContext, const cell_t *params) +{ + char *pOutput; + pContext->LocalToString(params[2], &pOutput); + + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(gamehelpers->IndexToReference(params[1])); + CBaseEntityOutput *pEntityOutput = GetOutput(pEntity, pOutput); + + if(pEntityOutput == NULL || pEntityOutput->m_ActionList == NULL) + return -1; + + return pEntityOutput->DeleteAllElements(); } @@ -270,9 +399,39 @@ const sp_nativeinfo_t MyNatives[] = { "GetOutputTargetInput", GetOutputTargetInput }, { "GetOutputParameter", GetOutputParameter }, { "GetOutputDelay", GetOutputDelay }, + { "GetOutputFormatted", GetOutputFormatted }, + { "FindOutput", FindOutput }, + { "DeleteOutput", DeleteOutput }, + { "DeleteAllOutputs", DeleteAllOutputs }, { NULL, NULL }, }; +bool Outputinfo::SDK_OnLoad(char *error, size_t maxlen, bool late) +{ + char conf_error[255] = ""; + if(!gameconfs->LoadGameConfigFile("outputinfo", &g_pGameConf, conf_error, sizeof(conf_error))) + { + if(conf_error[0]) + { + snprintf(error, maxlen, "Could not read outputinfo.txt: %s\n", conf_error); + } + return false; + } + + if(!g_pGameConf->GetMemSig("CEventAction__operator_delete", (void **)(&CEventAction::s_pOperatorDeleteFunc)) || !CEventAction::s_pOperatorDeleteFunc) + { + snprintf(error, maxlen, "Failed to find CEventAction__operator_delete function.\n"); + return false; + } + + return true; +} + +void Outputinfo::SDK_OnUnload() +{ + gameconfs->CloseGameConfigFile(g_pGameConf); +} + void Outputinfo::SDK_OnAllLoaded() { sharesys->AddNatives(myself, MyNatives); diff --git a/extension.h b/extension.h index 96d3a07..41b6f8d 100644 --- a/extension.h +++ b/extension.h @@ -55,12 +55,12 @@ public: * @param late Whether or not the module was loaded after map load. * @return True to succeed loading, false to fail. */ - //virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); + virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); /** * @brief This is called right before the extension is unloaded. */ - //virtual void SDK_OnUnload(); + virtual void SDK_OnUnload(); /** * @brief This is called once all known extensions have been loaded. diff --git a/gamedata/outputinfo.txt b/gamedata/outputinfo.txt new file mode 100644 index 0000000..4ba248d --- /dev/null +++ b/gamedata/outputinfo.txt @@ -0,0 +1,14 @@ +"Games" +{ + "#default" + { + "Signatures" + { + "CEventAction__operator_delete" + { + "library" "server" + "linux" "@_ZN12CEventActiondlEPv" + } + } + } +} diff --git a/include/outputinfo.inc b/include/outputinfo.inc index 3624c3e..d7c864a 100644 --- a/include/outputinfo.inc +++ b/include/outputinfo.inc @@ -4,10 +4,20 @@ #define _OutputInfo_Included native int GetOutputCount(int Entity, const char[] sOutput); -native int GetOutputTarget(int Entity, const char[] sOutput, int Index, char[] sTarget); -native int GetOutputTargetInput(int Entity, const char[] sOutput, int Index, char[] sTargetInput); -native int GetOutputParameter(int Entity, const char[] sOutput, int Index, char[] sParameter); +native int GetOutputTarget(int Entity, const char[] sOutput, int Index, char[] sTarget, int MaxLen); +native int GetOutputTargetInput(int Entity, const char[] sOutput, int Index, char[] sTargetInput, int MaxLen); +native int GetOutputParameter(int Entity, const char[] sOutput, int Index, char[] sParameter, int MaxLen); native float GetOutputDelay(int Entity, const char[] sOutput, int Index); +native int GetOutputFormatted(int Entity, const char[] sOutput, int Index, char[] sFormatted, int MaxLen); +native int FindOutput(int Entity, const char[] sOutput, int StartIndex, + const char[] sTarget = NULL_STRING, // or NULL_STRING to ignore + const char[] sTargetInput = NULL_STRING, // or NULL_STRING to ignore + const char[] sParameter = NULL_STRING, // or NULL_STRING to ignore + float fDelay = -1.0, // or -1.0 to ignore + int TimesToFire = 0 // or 0 to ignore + ); +native int DeleteOutput(int Entity, const char[] sOutput, int Index); +native int DeleteAllOutputs(int Entity, const char[] sOutput); /** * Do not edit below this line! @@ -36,5 +46,9 @@ public __ext_outputinfo_SetNTVOptional() MarkNativeAsOptional("GetOutputTargetInput"); MarkNativeAsOptional("GetOutputParameter"); MarkNativeAsOptional("GetOutputDelay"); + MarkNativeAsOptional("GetOutputFormatted"); + MarkNativeAsOptional("FindOutput"); + MarkNativeAsOptional("DeleteOutput"); + MarkNativeAsOptional("DeleteAllOutputs"); } #endif diff --git a/smsdk_config.h b/smsdk_config.h index 79885dc..9006c1e 100644 --- a/smsdk_config.h +++ b/smsdk_config.h @@ -40,7 +40,7 @@ /* Basic information exposed publicly */ #define SMEXT_CONF_NAME "OutputInfo" #define SMEXT_CONF_DESCRIPTION "Read entity outputs" -#define SMEXT_CONF_VERSION "0.1" +#define SMEXT_CONF_VERSION "1.0" #define SMEXT_CONF_AUTHOR "BotoX" #define SMEXT_CONF_URL "" #define SMEXT_CONF_LOGTAG "OUTPUTINFO" @@ -63,7 +63,7 @@ //#define SMEXT_ENABLE_HANDLESYS //#define SMEXT_ENABLE_PLAYERHELPERS //#define SMEXT_ENABLE_DBMANAGER -//#define SMEXT_ENABLE_GAMECONF +#define SMEXT_ENABLE_GAMECONF //#define SMEXT_ENABLE_MEMUTILS #define SMEXT_ENABLE_GAMEHELPERS //#define SMEXT_ENABLE_TIMERSYS