Add FrameIterator to SourceMod (#716).
* Create FrameIterator type This commit adds the FrameIterator type to core sm along with a few methods around getting the information for each frame. * Fix incorrect documentation [skip ci] * Implement KyleS's Changes * A nit
This commit is contained in:
parent
7507672895
commit
43cdf20fd3
@ -82,6 +82,7 @@ binary.sources += [
|
|||||||
'CDataPack.cpp',
|
'CDataPack.cpp',
|
||||||
'frame_tasks.cpp',
|
'frame_tasks.cpp',
|
||||||
'smn_halflife.cpp',
|
'smn_halflife.cpp',
|
||||||
|
'FrameIterator.cpp',
|
||||||
]
|
]
|
||||||
if builder.target.platform == 'windows':
|
if builder.target.platform == 'windows':
|
||||||
binary.sources += ['thread/WinThreads.cpp']
|
binary.sources += ['thread/WinThreads.cpp']
|
||||||
|
96
core/logic/FrameIterator.cpp
Normal file
96
core/logic/FrameIterator.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2017 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FrameIterator.h"
|
||||||
|
|
||||||
|
SafeFrameIterator::SafeFrameIterator(IFrameIterator *it)
|
||||||
|
{
|
||||||
|
while (!it->Done())
|
||||||
|
{
|
||||||
|
FrameInfo info = FrameInfo(it);
|
||||||
|
frames.append(info);
|
||||||
|
it->Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
it->Reset();
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SafeFrameIterator::Done() const
|
||||||
|
{
|
||||||
|
return current == frames.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SafeFrameIterator::Next()
|
||||||
|
{
|
||||||
|
if (!this->Done())
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SafeFrameIterator::Reset()
|
||||||
|
{
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SafeFrameIterator::LineNumber() const
|
||||||
|
{
|
||||||
|
if (this->Done())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)frames[current].LineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *SafeFrameIterator::FunctionName() const
|
||||||
|
{
|
||||||
|
if (this->Done())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames[current].FunctionName.chars();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *SafeFrameIterator::FilePath() const
|
||||||
|
{
|
||||||
|
if (this->Done())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames[current].FilePath.chars();
|
||||||
|
}
|
77
core/logic/FrameIterator.h
Normal file
77
core/logic/FrameIterator.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2017 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.sourcemod.net/license.php>.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sp_vm_api.h"
|
||||||
|
#include <am-vector.h>
|
||||||
|
#include <am-string.h>
|
||||||
|
|
||||||
|
using namespace SourcePawn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frame iterator cache which is safe for plugins to hold handles to,
|
||||||
|
* unlike what you'd recieve from IPluginContext::CreateFrameIterator.
|
||||||
|
*/
|
||||||
|
class SafeFrameIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct which holds all of the cached values for each individual frame.
|
||||||
|
*/
|
||||||
|
struct FrameInfo
|
||||||
|
{
|
||||||
|
ke::AString FunctionName;
|
||||||
|
ke::AString FilePath;
|
||||||
|
unsigned LineNumber;
|
||||||
|
|
||||||
|
FrameInfo(IFrameIterator *it)
|
||||||
|
{
|
||||||
|
LineNumber = it->LineNumber();
|
||||||
|
|
||||||
|
FunctionName = it->FunctionName();
|
||||||
|
FilePath = it->FilePath();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SafeFrameIterator(IFrameIterator *);
|
||||||
|
|
||||||
|
bool Done() const;
|
||||||
|
bool Next();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
int LineNumber() const;
|
||||||
|
const char *FunctionName() const;
|
||||||
|
const char *FilePath() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t current;
|
||||||
|
ke::Vector<FrameInfo> frames;
|
||||||
|
};
|
@ -2,7 +2,7 @@
|
|||||||
* vim: set ts=4 sw=4 tw=99 noet :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2017 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#include <ISourceMod.h>
|
#include <ISourceMod.h>
|
||||||
#include <ITranslator.h>
|
#include <ITranslator.h>
|
||||||
|
#include <DebugReporter.h>
|
||||||
|
#include <FrameIterator.h>
|
||||||
|
|
||||||
#include <sourcehook.h>
|
#include <sourcehook.h>
|
||||||
#include <sh_memory.h>
|
#include <sh_memory.h>
|
||||||
@ -59,6 +61,7 @@ using namespace SourcePawn;
|
|||||||
|
|
||||||
|
|
||||||
HandleType_t g_PlIter;
|
HandleType_t g_PlIter;
|
||||||
|
HandleType_t g_FrameIter;
|
||||||
|
|
||||||
IForward *g_OnLogAction = NULL;
|
IForward *g_OnLogAction = NULL;
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ public:
|
|||||||
hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
|
hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
|
||||||
|
|
||||||
g_PlIter = handlesys->CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
g_PlIter = handlesys->CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||||
|
g_FrameIter = handlesys->CreateType("FrameIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||||
|
|
||||||
g_OnLogAction = forwardsys->CreateForward("OnLogAction",
|
g_OnLogAction = forwardsys->CreateForward("OnLogAction",
|
||||||
ET_Hook,
|
ET_Hook,
|
||||||
@ -90,14 +94,22 @@ public:
|
|||||||
sm_datetime_format = bridge->FindConVar("sm_datetime_format");
|
sm_datetime_format = bridge->FindConVar("sm_datetime_format");
|
||||||
}
|
}
|
||||||
void OnHandleDestroy(HandleType_t type, void *object)
|
void OnHandleDestroy(HandleType_t type, void *object)
|
||||||
|
{
|
||||||
|
if (type == g_FrameIter)
|
||||||
|
{
|
||||||
|
delete (SafeFrameIterator *) object;
|
||||||
|
}
|
||||||
|
else if (type == g_PlIter)
|
||||||
{
|
{
|
||||||
IPluginIterator *iter = (IPluginIterator *)object;
|
IPluginIterator *iter = (IPluginIterator *)object;
|
||||||
iter->Release();
|
iter->Release();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void OnSourceModShutdown()
|
void OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
forwardsys->ReleaseForward(g_OnLogAction);
|
forwardsys->ReleaseForward(g_OnLogAction);
|
||||||
handlesys->RemoveType(g_PlIter, g_pCoreIdent);
|
handlesys->RemoveType(g_PlIter, g_pCoreIdent);
|
||||||
|
handlesys->RemoveType(g_FrameIter, g_pCoreIdent);
|
||||||
}
|
}
|
||||||
} g_CoreNativeHelpers;
|
} g_CoreNativeHelpers;
|
||||||
|
|
||||||
@ -780,6 +792,143 @@ static cell_t IsNullString(IPluginContext *pContext, const cell_t *params)
|
|||||||
return str == nullptr;
|
return str == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_Create(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
IFrameIterator *it = pContext->CreateFrameIterator();
|
||||||
|
|
||||||
|
SafeFrameIterator *iterator = new SafeFrameIterator(it);
|
||||||
|
|
||||||
|
pContext->DestroyFrameIterator(it);
|
||||||
|
|
||||||
|
Handle_t handle = handlesys->CreateHandle(g_FrameIter, iterator, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||||
|
if (handle == BAD_HANDLE)
|
||||||
|
{
|
||||||
|
delete iterator;
|
||||||
|
return BAD_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_Next(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
|
HandleError err;
|
||||||
|
SafeFrameIterator *iterator;
|
||||||
|
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
|
||||||
|
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator->Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_Reset(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
|
HandleError err;
|
||||||
|
SafeFrameIterator *iterator;
|
||||||
|
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
|
||||||
|
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator->Reset();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_LineNumber(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
|
HandleError err;
|
||||||
|
SafeFrameIterator *iterator;
|
||||||
|
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
|
||||||
|
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineNum = iterator->LineNumber();
|
||||||
|
if (lineNum < 0)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_GetFunctionName(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
|
HandleError err;
|
||||||
|
SafeFrameIterator *iterator;
|
||||||
|
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
|
||||||
|
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* functionName = iterator->FunctionName();
|
||||||
|
if (!functionName)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buffer;
|
||||||
|
pContext->LocalToString(params[2], &buffer);
|
||||||
|
size_t size = static_cast<size_t>(params[3]);
|
||||||
|
|
||||||
|
ke::SafeStrcpy(buffer, size, functionName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t FrameIterator_GetFilePath(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
|
HandleError err;
|
||||||
|
SafeFrameIterator *iterator;
|
||||||
|
|
||||||
|
HandleSecurity sec;
|
||||||
|
sec.pIdentity = g_pCoreIdent;
|
||||||
|
sec.pOwner = pContext->GetIdentity();
|
||||||
|
|
||||||
|
if ((err=handlesys->ReadHandle(hndl, g_FrameIter, &sec, (void **)&iterator)) != HandleError_None)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* filePath = iterator->FilePath();
|
||||||
|
if (!filePath)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Iterator out of bounds. Check return value of FrameIterator.Next");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buffer;
|
||||||
|
pContext->LocalToString(params[2], &buffer);
|
||||||
|
size_t size = static_cast<size_t>(params[3]);
|
||||||
|
|
||||||
|
ke::SafeStrcpy(buffer, size, filePath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(coreNatives)
|
REGISTER_NATIVES(coreNatives)
|
||||||
{
|
{
|
||||||
{"ThrowError", ThrowError},
|
{"ThrowError", ThrowError},
|
||||||
@ -810,5 +959,12 @@ REGISTER_NATIVES(coreNatives)
|
|||||||
{"StoreToAddress", StoreToAddress},
|
{"StoreToAddress", StoreToAddress},
|
||||||
{"IsNullVector", IsNullVector},
|
{"IsNullVector", IsNullVector},
|
||||||
{"IsNullString", IsNullString},
|
{"IsNullString", IsNullString},
|
||||||
|
|
||||||
|
{"FrameIterator.FrameIterator", FrameIterator_Create},
|
||||||
|
{"FrameIterator.Next", FrameIterator_Next},
|
||||||
|
{"FrameIterator.Reset", FrameIterator_Reset},
|
||||||
|
{"FrameIterator.LineNumber.get", FrameIterator_LineNumber},
|
||||||
|
{"FrameIterator.GetFunctionName", FrameIterator_GetFunctionName},
|
||||||
|
{"FrameIterator.GetFilePath", FrameIterator_GetFilePath},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
@ -645,6 +645,37 @@ native int LoadFromAddress(Address addr, NumberType size);
|
|||||||
*/
|
*/
|
||||||
native void StoreToAddress(Address addr, int data, NumberType size);
|
native void StoreToAddress(Address addr, int data, NumberType size);
|
||||||
|
|
||||||
|
methodmap FrameIterator < Handle {
|
||||||
|
// Creates a stack frame iterator to build your own stack traces.
|
||||||
|
// @return New handle to a FrameIterator.
|
||||||
|
public native FrameIterator();
|
||||||
|
|
||||||
|
// Advances the iterator to the next stack frame.
|
||||||
|
// @return True if another frame was fetched and data can be successfully read.
|
||||||
|
// @error No next element exception.
|
||||||
|
public native bool Next();
|
||||||
|
|
||||||
|
// Resets the iterator back to it's starting position.
|
||||||
|
public native void Reset();
|
||||||
|
|
||||||
|
// Returns the line number of the current function call.
|
||||||
|
property bool LineNumber {
|
||||||
|
public native get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the name of the current function in the call stack.
|
||||||
|
//
|
||||||
|
// @param buffer Buffer to copy to.
|
||||||
|
// @param maxlen Max size of the buffer.
|
||||||
|
public native void GetFunctionName(char[] buffer, int maxlen);
|
||||||
|
|
||||||
|
// Gets the file path to the current call in the call stack.
|
||||||
|
//
|
||||||
|
// @param buffer Buffer to copy to.
|
||||||
|
// @param maxlen Max size of the buffer.
|
||||||
|
public native void GetFilePath(char[] buffer, int maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
#include <helpers>
|
#include <helpers>
|
||||||
#include <entity>
|
#include <entity>
|
||||||
#include <entity_prop_stocks>
|
#include <entity_prop_stocks>
|
||||||
|
Loading…
Reference in New Issue
Block a user