mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-07 02:18:35 +00:00
Introduce MemoryPointer
This commit is contained in:
parent
b7feeef350
commit
33102593bc
@ -86,6 +86,7 @@ for cxx in builder.targets:
|
||||
'DatabaseConfBuilder.cpp',
|
||||
'LumpManager.cpp',
|
||||
'smn_entitylump.cpp',
|
||||
'MemoryPointer.cpp'
|
||||
]
|
||||
|
||||
if binary.compiler.target.arch == 'x86_64':
|
||||
|
||||
61
core/logic/MemoryPointer.cpp
Normal file
61
core/logic/MemoryPointer.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2024 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 "MemoryPointer.h"
|
||||
#include <sourcehook.h>
|
||||
#include <sh_memory.h>
|
||||
#include <algorithm>
|
||||
|
||||
MemoryPointer::MemoryPointer(cell_t size) : m_ptr(malloc(size)), m_owned(true), m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryPointer::MemoryPointer(void* ptr, cell_t size) : m_ptr(ptr), m_owned(false), m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryPointer::~MemoryPointer()
|
||||
{
|
||||
if (m_owned)
|
||||
{
|
||||
free(m_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void* MemoryPointer::Get()
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
cell_t MemoryPointer::GetSize()
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
53
core/logic/MemoryPointer.h
Normal file
53
core/logic/MemoryPointer.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2024 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$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <sp_vm_types.h>
|
||||
#include <IMemoryPointer.h>
|
||||
|
||||
class MemoryPointer : public SourceMod::IMemoryPointer
|
||||
{
|
||||
public:
|
||||
MemoryPointer(cell_t size);
|
||||
MemoryPointer(void* ptr, cell_t size);
|
||||
|
||||
// SourceMod::IMemoryPointer
|
||||
virtual ~MemoryPointer();
|
||||
virtual void* Get() override;
|
||||
virtual cell_t GetSize() override;
|
||||
protected:
|
||||
void* m_ptr;
|
||||
bool m_owned;
|
||||
cell_t m_size;
|
||||
};
|
||||
@ -42,6 +42,7 @@
|
||||
#include <ITranslator.h>
|
||||
#include <DebugReporter.h>
|
||||
#include <FrameIterator.h>
|
||||
#include <MemoryPointer.h>
|
||||
|
||||
#include <sourcehook.h>
|
||||
#include <sh_memory.h>
|
||||
@ -67,6 +68,7 @@ using namespace SourcePawn;
|
||||
|
||||
HandleType_t g_PlIter;
|
||||
HandleType_t g_FrameIter;
|
||||
HandleType_t g_MemoryPtr;
|
||||
|
||||
IForward *g_OnLogAction = NULL;
|
||||
|
||||
@ -86,6 +88,12 @@ public:
|
||||
g_PlIter = handlesys->CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
g_FrameIter = handlesys->CreateType("FrameIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
HandleAccess security;
|
||||
security.access[HandleAccess_Read] = 0;
|
||||
security.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
|
||||
security.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
|
||||
g_MemoryPtr = handlesys->CreateType("MemoryPointer", this, 0, NULL, &security, g_pCoreIdent, NULL);
|
||||
|
||||
g_OnLogAction = forwardsys->CreateForward("OnLogAction",
|
||||
ET_Hook,
|
||||
5,
|
||||
@ -100,7 +108,11 @@ public:
|
||||
}
|
||||
void OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
if (type == g_FrameIter)
|
||||
if (type == g_MemoryPtr)
|
||||
{
|
||||
delete (IMemoryPointer *) object;
|
||||
}
|
||||
else if (type == g_FrameIter)
|
||||
{
|
||||
delete (SafeFrameIterator *) object;
|
||||
}
|
||||
@ -115,6 +127,7 @@ public:
|
||||
forwardsys->ReleaseForward(g_OnLogAction);
|
||||
handlesys->RemoveType(g_PlIter, g_pCoreIdent);
|
||||
handlesys->RemoveType(g_FrameIter, g_pCoreIdent);
|
||||
handlesys->RemoveType(g_MemoryPtr, g_pCoreIdent);
|
||||
}
|
||||
} g_CoreNativeHelpers;
|
||||
|
||||
@ -971,6 +984,90 @@ static cell_t IsNullString(IPluginContext *pContext, const cell_t *params)
|
||||
return str == nullptr;
|
||||
}
|
||||
|
||||
static cell_t MemoryPointer_Create(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
auto ptr = new MemoryPointer(params[1]);
|
||||
|
||||
Handle_t handle = handlesys->CreateHandle(g_MemoryPtr, ptr, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
if (handle == BAD_HANDLE)
|
||||
{
|
||||
delete ptr;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static cell_t MemoryPointer_Store(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IMemoryPointer *ptr;
|
||||
|
||||
HandleSecurity sec;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
sec.pOwner = pContext->GetIdentity();
|
||||
|
||||
if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
unsigned int bytesSize = 0;
|
||||
switch (params[3])
|
||||
{
|
||||
case NumberType_Int8:
|
||||
bytesSize = sizeof(std::uint8_t);
|
||||
break;
|
||||
case NumberType_Int16:
|
||||
bytesSize = sizeof(std::uint16_t);
|
||||
break;
|
||||
case NumberType_Int32:
|
||||
bytesSize = sizeof(std::uint32_t);
|
||||
break;
|
||||
default:
|
||||
return pContext->ThrowNativeError("Invalid number types %d", params[3]);
|
||||
}
|
||||
|
||||
ptr->Store(params[2], bytesSize, params[4], params[5] != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t MemoryPointer_Load(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IMemoryPointer *ptr;
|
||||
|
||||
HandleSecurity sec;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
sec.pOwner = pContext->GetIdentity();
|
||||
|
||||
if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
unsigned int bytesSize = 0;
|
||||
switch (params[2])
|
||||
{
|
||||
case NumberType_Int8:
|
||||
bytesSize = sizeof(std::uint8_t);
|
||||
break;
|
||||
case NumberType_Int16:
|
||||
bytesSize = sizeof(std::uint16_t);
|
||||
break;
|
||||
case NumberType_Int32:
|
||||
bytesSize = sizeof(std::uint32_t);
|
||||
break;
|
||||
default:
|
||||
return pContext->ThrowNativeError("Invalid number types %d", params[2]);
|
||||
}
|
||||
|
||||
return ptr->Load(bytesSize, params[3]);
|
||||
}
|
||||
|
||||
static cell_t FrameIterator_Create(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IFrameIterator *it = pContext->CreateFrameIterator();
|
||||
@ -1161,6 +1258,10 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"IsNullString", IsNullString},
|
||||
{"LogStackTrace", LogStackTrace},
|
||||
|
||||
{"MemoryPointer.MemoryPointer", MemoryPointer_Create},
|
||||
{"MemoryPointer.Store", MemoryPointer_Store},
|
||||
{"MemoryPointer.Load", MemoryPointer_Load},
|
||||
|
||||
{"FrameIterator.FrameIterator", FrameIterator_Create},
|
||||
{"FrameIterator.Next", FrameIterator_Next},
|
||||
{"FrameIterator.Reset", FrameIterator_Reset},
|
||||
|
||||
@ -92,6 +92,7 @@ SourceHook::CallClass<IVEngineServer> *enginePatch = NULL;
|
||||
SourceHook::CallClass<IEngineSound> *enginesoundPatch = NULL;
|
||||
HandleType_t g_CallHandle = 0;
|
||||
HandleType_t g_TraceHandle = 0;
|
||||
HandleType_t g_MemPtrHandle = 0;
|
||||
ISDKTools *g_pSDKTools;
|
||||
|
||||
SMEXT_LINK(&g_SdkTools);
|
||||
@ -169,6 +170,12 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handlesys->FindHandleType("MemoryPointer", &g_MemPtrHandle))
|
||||
{
|
||||
ke::SafeSprintf(error, maxlength, "Could not find MemoryPointer handle type");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
g_pCVar = icvar;
|
||||
#endif
|
||||
|
||||
@ -174,6 +174,7 @@ extern IGameHelpers *g_pGameHelpers;
|
||||
/* Handle types */
|
||||
extern HandleType_t g_CallHandle;
|
||||
extern HandleType_t g_TraceHandle;
|
||||
extern HandleType_t g_MemPtrHandle;
|
||||
/* Call Wrappers */
|
||||
extern ICallWrapper *g_pAcceptInput;
|
||||
/* Timers */
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "extension.h"
|
||||
#include "vcallbuilder.h"
|
||||
#include "vglobals.h"
|
||||
#include "IMemoryPointer.h"
|
||||
|
||||
enum SDKLibrary
|
||||
{
|
||||
@ -63,7 +64,8 @@ inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &ty
|
||||
type = PassType_Basic;
|
||||
if (vtype == Valve_POD
|
||||
|| vtype == Valve_Float
|
||||
|| vtype == Valve_Bool)
|
||||
|| vtype == Valve_Bool
|
||||
|| vtype == Valve_MemoryPointer)
|
||||
{
|
||||
flags = PASSFLAG_BYVAL | PASSFLAG_ASPOINTER;
|
||||
} else {
|
||||
@ -413,6 +415,44 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
case ValveCall_MemoryPointer:
|
||||
{
|
||||
//params[startparam] is an address to a pointer to THIS
|
||||
//params following this are params to the method we will invoke later
|
||||
if (startparam > numparams)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Expected a ThisPtr address, it wasn't found");
|
||||
}
|
||||
|
||||
//note: varargs pawn args are passed by-ref
|
||||
cell_t *cell;
|
||||
pContext->LocalToPhysAddr(params[startparam], &cell);
|
||||
Handle_t hndl = (Handle_t)(*cell);
|
||||
|
||||
if (hndl == 0)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("MemoryPointer handle cannot be null");
|
||||
}
|
||||
|
||||
IMemoryPointer* memPtr = nullptr;
|
||||
|
||||
HandleSecurity security;
|
||||
security.pIdentity = myself->GetIdentity();
|
||||
security.pOwner = pContext->GetIdentity();
|
||||
|
||||
HandleError err = HandleError_None;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_MemPtrHandle, &security, (void **)&memPtr)) != HandleError_None)
|
||||
{
|
||||
pContext->ThrowNativeError("Could not read MemoryPointer Handle %x (error %d)", hndl, err);
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
*(void **)ptr = memPtr->Get();
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
@ -429,7 +469,8 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
startparam += 2;
|
||||
} else if (vc->retinfo->vtype == Valve_Vector
|
||||
|| vc->retinfo->vtype == Valve_QAngle)
|
||||
|| vc->retinfo->vtype == Valve_QAngle
|
||||
|| vc->retinfo->vtype == Valve_MemoryPointer)
|
||||
{
|
||||
startparam += 1;
|
||||
}
|
||||
@ -506,11 +547,12 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
pContext->StringToLocalUTF8(params[retparam], *addr, *(char **)vc->retbuf, &written);
|
||||
return (cell_t)written;
|
||||
} else if (vc->retinfo->vtype == Valve_Vector
|
||||
|| vc->retinfo->vtype == Valve_QAngle)
|
||||
|| vc->retinfo->vtype == Valve_QAngle
|
||||
|| vc->retinfo->vtype == Valve_MemoryPointer)
|
||||
{
|
||||
if (numparams < 2)
|
||||
{
|
||||
return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage");
|
||||
return pContext->ThrowNativeError("Expected argument (2) for return storage");
|
||||
}
|
||||
if (EncodeValveParam(pContext, params[retparam], vc, vc->retinfo, vc->retbuf)
|
||||
== Data_Fail)
|
||||
|
||||
@ -34,9 +34,31 @@
|
||||
#include "vdecoder.h"
|
||||
#include "vcallbuilder.h"
|
||||
|
||||
#include <IMemoryPointer.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourcePawn;
|
||||
|
||||
class ForeignMemoryPointer : public IMemoryPointer
|
||||
{
|
||||
public:
|
||||
ForeignMemoryPointer(void* ptr) : m_ptr(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* Get() override
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
virtual cell_t GetSize() override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
protected:
|
||||
void* m_ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* For object pointers, the data looks like this instead:
|
||||
* 4 bytes: POINTER TO LATER
|
||||
@ -164,6 +186,21 @@ size_t ValveParamToBinParam(ValveType type,
|
||||
return sizeof(float);
|
||||
}
|
||||
}
|
||||
case Valve_MemoryPointer:
|
||||
{
|
||||
info->flags = flags;
|
||||
if (flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
needs_extra = true;
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void**);
|
||||
return sizeof(void**) + sizeof(void*);
|
||||
} else {
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void*);
|
||||
return sizeof(void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -276,6 +313,37 @@ DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||
|
||||
*addr = *(bool *)buffer ? 1 : 0;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_MemoryPointer:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
if (data->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
buffer = *(void ***)buffer;
|
||||
}
|
||||
|
||||
auto ptr = *(void **)buffer;
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
*addr = 0;
|
||||
return Data_Okay;
|
||||
}
|
||||
|
||||
HandleError err = HandleError_None;
|
||||
Handle_t hndl = handlesys->CreateHandle(g_MemPtrHandle, new ForeignMemoryPointer(ptr), pContext->GetIdentity(), myself->GetIdentity(), &err);
|
||||
|
||||
if (err != HandleError_None)
|
||||
{
|
||||
pContext->ThrowNativeError("Failed to create MemoryPointer while decoding (error: %d)", err);
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
*addr = hndl;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
@ -579,6 +647,37 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
*(char **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_MemoryPointer:
|
||||
{
|
||||
IMemoryPointer* ptr = nullptr;
|
||||
|
||||
HandleSecurity security;
|
||||
security.pIdentity = myself->GetIdentity();
|
||||
security.pOwner = pContext->GetIdentity();
|
||||
|
||||
Handle_t hndl = (Handle_t)param;
|
||||
|
||||
if (hndl == 0)
|
||||
{
|
||||
if (data->decflags & VDECODE_FLAG_ALLOWNULL)
|
||||
{
|
||||
*(void **)buffer = nullptr;
|
||||
return Data_Okay;
|
||||
}
|
||||
pContext->ThrowNativeError("Null/Invalid Handle MemoryPointer isn't allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
HandleError err = HandleError_None;
|
||||
if ((err = handlesys->ReadHandle(hndl, g_MemPtrHandle, &security, (void **)&ptr)) != HandleError_None)
|
||||
{
|
||||
pContext->ThrowNativeError("Could not read MemoryPointer Handle %x (error %d)", hndl, err);
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
*(void **)buffer = ptr->Get();
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Data_Fail;
|
||||
|
||||
@ -53,6 +53,7 @@ enum ValveType
|
||||
Valve_Edict, /**< Edict */
|
||||
Valve_String, /**< String */
|
||||
Valve_Bool, /**< Boolean */
|
||||
Valve_MemoryPointer, /**< Sourcemod's IMemoryPointer */
|
||||
Valve_Object, /**< Object, not matching one of the above types */
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ enum ValveCallType
|
||||
ValveCall_Raw, /**< Thiscall (address explicit first parameter) */
|
||||
ValveCall_Server, /**< Thiscall (CBaseServer implicit first parameter) */
|
||||
ValveCall_Engine, /**< Thiscall (CVEngineServer implicit first parameter) */
|
||||
ValveCall_MemoryPointer /**< Thiscall (Sourcemod's IMemoryPointer handle implicit first parameter */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -62,7 +62,8 @@ enum SDKCallType
|
||||
SDKCall_EntityList, /**< CGlobalEntityList call */
|
||||
SDKCall_Raw, /**< |this| pointer with an arbitrary address */
|
||||
SDKCall_Server, /**< CBaseServer call */
|
||||
SDKCall_Engine /**< CVEngineServer call */
|
||||
SDKCall_Engine, /**< CVEngineServer call */
|
||||
SDKCall_MemoryPointer /**< |this| pointer retrieved from a MemoryPointer handle */
|
||||
};
|
||||
|
||||
enum SDKLibrary
|
||||
@ -88,7 +89,8 @@ enum SDKType
|
||||
SDKType_Float, /**< Float (any) */
|
||||
SDKType_Edict, /**< edict_t (always as pointer) */
|
||||
SDKType_String, /**< NULL-terminated string (always as pointer) */
|
||||
SDKType_Bool /**< Boolean (any) */
|
||||
SDKType_Bool, /**< Boolean (any) */
|
||||
SDKType_MemoryPointer /**< Sourcemod MemoryPointer handle */
|
||||
};
|
||||
|
||||
enum SDKPassMethod
|
||||
|
||||
@ -754,6 +754,25 @@ native any LoadFromAddress(Address addr, NumberType size);
|
||||
*/
|
||||
native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true);
|
||||
|
||||
methodmap MemoryPointer < Handle {
|
||||
// Creates a memory block of the given bytes size.
|
||||
// And wrap its pointer into a MemoryPointer handle.
|
||||
// @return New Handle to a memory pointer.
|
||||
public native MemoryPointer(int size);
|
||||
|
||||
// Stores the given data at the provided offset.
|
||||
// @param data The data to store.
|
||||
// @param size Size of the data to store.
|
||||
// @param offset Offset in bytes from the start.
|
||||
public native void Store(any data, NumberType size, int offset = 0, bool updateMemAccess = true);
|
||||
|
||||
// Retrieves the data at the provided offset.
|
||||
// @param size Size of the data to store.
|
||||
// @param offset Offset in bytes from the start.
|
||||
// @return The data that was stored.
|
||||
public native any Load(NumberType size, int offset = 0);
|
||||
};
|
||||
|
||||
methodmap FrameIterator < Handle {
|
||||
// Creates a stack frame iterator to build your own stack traces.
|
||||
// @return New handle to a FrameIterator.
|
||||
|
||||
107
public/IMemoryPointer.h
Normal file
107
public/IMemoryPointer.h
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2024 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$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sourcehook.h>
|
||||
#include <sh_memory.h>
|
||||
#include <cstdint>
|
||||
#include <sp_vm_types.h>
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
class IMemoryPointer
|
||||
{
|
||||
public:
|
||||
virtual ~IMemoryPointer() = default;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the underlying pointer.
|
||||
*
|
||||
* @return The underlying pointer.
|
||||
*/
|
||||
virtual void* Get() = 0;
|
||||
|
||||
/**
|
||||
* @brief Approximate size in bytes of the memory block pointed by the pointer.
|
||||
*
|
||||
* @return The pointed memory size in bytes, 0 if size is unknown.
|
||||
*/
|
||||
virtual cell_t GetSize() = 0;
|
||||
|
||||
/**
|
||||
* @brief Stores data at the given offset.
|
||||
*
|
||||
* @param data The data to store.
|
||||
* @param byteSize Size of the data in bytes.
|
||||
* @param offset Offset in bytes to store the data at.
|
||||
* @param updateMemAccess Whether or not to update the memory access before writing.
|
||||
*/
|
||||
virtual void Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess);
|
||||
|
||||
/**
|
||||
* @brief Loads data at the given offset.
|
||||
*
|
||||
* @param byteSize Size of the data in bytes.
|
||||
* @param offset Offset in bytes to read the data at.
|
||||
* @return The data stored at the given offset.
|
||||
*/
|
||||
virtual cell_t Load(unsigned int byteSize, cell_t offset);
|
||||
};
|
||||
|
||||
inline void IMemoryPointer::Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess)
|
||||
{
|
||||
auto ptr = &(((std::int8_t*)this->Get())[offset]);
|
||||
if (updateMemAccess)
|
||||
{
|
||||
SourceHook::SetMemAccess(ptr, byteSize, SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
|
||||
}
|
||||
|
||||
memcpy(ptr, &data, byteSize);
|
||||
}
|
||||
|
||||
inline cell_t IMemoryPointer::Load(unsigned int byteSize, cell_t offset)
|
||||
{
|
||||
auto ptr = &(((std::int8_t*)this->Get())[offset]);
|
||||
|
||||
switch(byteSize)
|
||||
{
|
||||
case 1:
|
||||
return *(std::int8_t*)(ptr);
|
||||
case 2:
|
||||
return *(std::int16_t*)(ptr);
|
||||
case 4:
|
||||
return *(std::int32_t*)(ptr);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user