complete the natives

This commit is contained in:
Kenzzer 2024-07-27 19:49:19 +02:00
parent 33102593bc
commit b02445be7a
No known key found for this signature in database
GPG Key ID: A4474D96720FD722
11 changed files with 427 additions and 6 deletions

View File

@ -50,6 +50,11 @@ MemoryPointer::~MemoryPointer()
}
}
void MemoryPointer::Delete()
{
delete this;
}
void* MemoryPointer::Get()
{
return m_ptr;

View File

@ -44,6 +44,7 @@ public:
// SourceMod::IMemoryPointer
virtual ~MemoryPointer();
virtual void Delete() override;
virtual void* Get() override;
virtual cell_t GetSize() override;
protected:

View File

@ -110,7 +110,7 @@ public:
{
if (type == g_MemoryPtr)
{
delete (IMemoryPointer *) object;
((IMemoryPointer *)object)->Delete();
}
else if (type == g_FrameIter)
{
@ -1068,6 +1068,84 @@ static cell_t MemoryPointer_Load(IPluginContext *pContext, const cell_t *params)
return ptr->Load(bytesSize, params[3]);
}
static cell_t MemoryPointer_StoreMemoryPointer(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);
}
hndl = (Handle_t)params[2];
IMemoryPointer *store;
if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&store)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
ptr->StorePtr(store->Get(), params[3], params[4] != 0);
}
static cell_t MemoryPointer_LoadMemoryPointer(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);
}
auto newPtr = new MemoryPointer(ptr->LoadPtr(params[2]), 0);
Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (newHandle == BAD_HANDLE)
{
delete newPtr;
return BAD_HANDLE;
}
return newHandle;
}
static cell_t MemoryPointer_Offset(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);
}
auto newPtr = new MemoryPointer((void*)(((intptr_t)ptr->Get()) + params[2]), 0);
Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (newHandle == BAD_HANDLE)
{
delete newPtr;
return BAD_HANDLE;
}
return newHandle;
}
static cell_t FrameIterator_Create(IPluginContext *pContext, const cell_t *params)
{
IFrameIterator *it = pContext->CreateFrameIterator();
@ -1261,6 +1339,9 @@ REGISTER_NATIVES(coreNatives)
{"MemoryPointer.MemoryPointer", MemoryPointer_Create},
{"MemoryPointer.Store", MemoryPointer_Store},
{"MemoryPointer.Load", MemoryPointer_Load},
{"MemoryPointer.StoreMemoryPointer", MemoryPointer_StoreMemoryPointer},
{"MemoryPointer.LoadMemoryPointer", MemoryPointer_LoadMemoryPointer},
{"MemoryPointer.Offset", MemoryPointer_Offset},
{"FrameIterator.FrameIterator", FrameIterator_Create},
{"FrameIterator.Next", FrameIterator_Next},

View File

@ -31,6 +31,7 @@
#include "common_logic.h"
#include <IHandleSys.h>
#include "MemoryPointer.h"
#include "GameConfigs.h"
HandleType_t g_GameConfigsType;
@ -194,6 +195,78 @@ static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
#endif
}
extern HandleType_t g_MemoryPtr;
static cell_t smn_GameConfGetAddressEx(IPluginContext *pCtx, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IGameConfig *gc;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc))
!= HandleError_None)
{
return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr);
}
char *key;
void* val;
pCtx->LocalToString(params[2], &key);
if (!gc->GetAddress(key, &val) || val == nullptr)
return BAD_HANDLE;
auto newPtr = new MemoryPointer(val, 0);
Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pCtx->GetIdentity(), g_pCoreIdent, NULL);
if (newHandle == BAD_HANDLE)
{
delete newPtr;
return BAD_HANDLE;
}
return newHandle;
}
static cell_t smn_GameConfGetMemSigEx(IPluginContext *pCtx, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IGameConfig *gc;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc))
!= HandleError_None)
{
return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr);
}
char *key;
void *val;
pCtx->LocalToString(params[2], &key);
if (!gc->GetMemSig(key, &val) || val == nullptr)
{
return BAD_HANDLE;
}
auto newPtr = new MemoryPointer(val, 0);
Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pCtx->GetIdentity(), g_pCoreIdent, NULL);
if (newHandle == BAD_HANDLE)
{
delete newPtr;
return BAD_HANDLE;
}
return newHandle;
}
static GameConfigsNatives s_GameConfigsNatives;
REGISTER_NATIVES(gameconfignatives)
@ -207,6 +280,10 @@ REGISTER_NATIVES(gameconfignatives)
{"GameData.GameData", smn_LoadGameConfigFile},
{"GameData.GetOffset", smn_GameConfGetOffset},
{"GameData.GetKeyValue", smn_GameConfGetKeyValue},
{"GameData.GetAddressEx", smn_GameConfGetAddressEx},
{"GameData.GetMemSigEx", smn_GameConfGetMemSigEx},
// Deprecated
{"GameData.GetAddress", smn_GameConfGetAddress},
{"GameData.GetMemSig", smn_GameConfGetMemSig},
{NULL, NULL}

View File

@ -35,6 +35,7 @@
#include "PlayerManager.h"
#include "HalfLife2.h"
#include <IGameConfigs.h>
#include <IMemoryPointer.h>
#include "sm_stringutil.h"
#include "logic_bridge.h"
@ -76,6 +77,44 @@
// Not defined in the sdk as we have no clue what it is
#define FL_EP2V_UNKNOWN (1 << 2)
HandleType_t g_MemoryPtr = 0;
class SimpleMemoryPointer : IMemoryPointer
{
public:
SimpleMemoryPointer(void* ptr) : m_ptr(ptr)
{
}
virtual void Delete()
{
delete this;
}
virtual cell_t GetSize() override
{
return 0;
}
virtual void* Get() override
{
return m_ptr;
}
protected:
void* m_ptr;
};
class EntitiesHelpers :
public SMGlobalClass
{
public:
virtual void OnSourceModAllInitialized_Post()
{
// This should never fail
handlesys->FindHandleType("MemoryPointer", &g_MemoryPtr);
}
} s_ConsoleHelpers;
enum PropType
{
Prop_Send = 0,
@ -2779,6 +2818,87 @@ static cell_t GetEntityAddress(IPluginContext *pContext, const cell_t *params)
#endif
}
static cell_t GetEntityMemoryPointer(IPluginContext *pContext, const cell_t *params)
{
CBaseEntity * pEntity = GetEntity(params[1]);
if (!pEntity)
{
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
auto newPtr = new SimpleMemoryPointer(pEntity);
Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (newHandle == BAD_HANDLE)
{
delete newPtr;
return BAD_HANDLE;
}
return newHandle;
}
static cell_t MemoryPointer_StoreEntityToHandle(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);
}
CBaseHandle &entityHandle = *reinterpret_cast<CBaseHandle*>(((intptr_t)ptr->Get()) + params[3]);
if ((unsigned)params[2] == INVALID_EHANDLE_INDEX)
{
entityHandle.Set(NULL);
}
else
{
CBaseEntity *pOther = GetEntity(params[2]);
if (!pOther)
{
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[2]), params[2]);
}
IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
entityHandle.Set(pHandleEnt);
}
return 0;
}
static cell_t MemoryPointer_LoadEntityFromHandle(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);
}
CBaseHandle &entityHandle = *reinterpret_cast<CBaseHandle*>(((intptr_t)ptr->Get()) + params[2]);
CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(entityHandle.GetEntryIndex());
if (!pHandleEntity || entityHandle != reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
{
return -1;
}
return g_HL2.EntityToBCompatRef(pHandleEntity);
}
REGISTER_NATIVES(entityNatives)
{
{"ChangeEdictState", ChangeEdictState},
@ -2823,8 +2943,11 @@ REGISTER_NATIVES(entityNatives)
{"SetEntPropString", SetEntPropString},
{"SetEntPropVector", SetEntPropVector},
{"GetEntityAddress", GetEntityAddress},
{"GetEntityMemoryPointer", GetEntityMemoryPointer},
{"FindDataMapInfo", FindDataMapInfo},
{"LoadEntityFromHandleAddress", LoadEntityFromHandleAddress},
{"StoreEntityToHandleAddress", StoreEntityToHandleAddress},
{"MemoryPointer.StoreEntityToHandle", MemoryPointer_StoreEntityToHandle},
{"MemoryPointer.LoadEntityFromHandle", MemoryPointer_LoadEntityFromHandle},
{NULL, NULL}
};

View File

@ -183,6 +183,25 @@ static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *par
return (s_call_addr != NULL) ? 1 : 0;
}
static cell_t PrepSDKCall_SetAddressFromMemoryPointer(IPluginContext *pContext, const cell_t *params)
{
IMemoryPointer* memPtr = nullptr;
HandleSecurity security;
security.pIdentity = myself->GetIdentity();
security.pOwner = pContext->GetIdentity();
HandleError err = HandleError_None;
Handle_t hndl = (Handle_t)params[1];
if ((err = handlesys->ReadHandle(hndl, g_MemPtrHandle, &security, (void **)&memPtr)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read MemoryPointer Handle %x (error %d)", hndl, err);
}
s_call_addr = memPtr->Get();
return (s_call_addr != NULL) ? 1 : 0;
}
// Must match same enum in sdktools.inc
enum SDKFuncConfSource
{
@ -597,6 +616,7 @@ sp_nativeinfo_t g_CallNatives[] =
{"PrepSDKCall_SetVirtual", PrepSDKCall_SetVirtual},
{"PrepSDKCall_SetSignature", PrepSDKCall_SetSignature},
{"PrepSDKCall_SetAddress", PrepSDKCall_SetAddress},
{"PrepSDKCall_SetAddressFromMemoryPointer", PrepSDKCall_SetAddressFromMemoryPointer},
{"PrepSDKCall_SetFromConf", PrepSDKCall_SetFromConf},
{"PrepSDKCall_SetReturnInfo", PrepSDKCall_SetReturnInfo},
{"PrepSDKCall_AddParameter", PrepSDKCall_AddParameter},

View File

@ -46,6 +46,11 @@ public:
{
}
virtual void Delete() override
{
delete this;
}
virtual void* Get() override
{
return m_ptr;

View File

@ -751,8 +751,18 @@ stock void SetEntDataArray(int entity, int offset, const any[] array, int arrayS
* @return Address of the entity.
* @error Invalid entity.
*/
#pragma deprecated Use GetEntityMemoryPointer instead
native Address GetEntityAddress(int entity);
/**
* Gets the memory address of an entity and wraps into a new MemoryPointer handle.
*
* @param entity Entity index.
* @return New MemoryPointer handle.
* @error Invalid entity.
*/
native MemoryPointer GetEntityMemoryPointer(int entity);
/**
* Retrieves the classname of an entity.
* This is like GetEdictClassname(), except it works for ALL
@ -774,6 +784,7 @@ stock bool GetEntityClassname(int entity, char[] clsname, int maxlength)
* @param addr Address to a memory location.
* @return Entity index at the given location. If there is no entity, or the stored entity is invalid, then -1 is returned.
*/
#pragma deprecated Use MemoryPointer.LoadEntityFromHandle instead
native int LoadEntityFromHandleAddress(Address addr);
/**
@ -782,4 +793,5 @@ native int LoadEntityFromHandleAddress(Address addr);
* @param addr Address to a memory location.
* @param entity Entity index to set, or -1 to clear.
*/
#pragma deprecated Use MemoryPointer.StoreEntityToHandle instead
native void StoreEntityToHandleAddress(Address addr, int entity);

View File

@ -140,8 +140,18 @@ native bool PrepSDKCall_SetSignature(SDKLibrary lib, const char[] signature, int
* @param addr Address of function to use.
* @return True on success, false on failure.
*/
#pragma deprecated Use PrepSDKCall_SetAddressFromMemoryPointer instead
native bool PrepSDKCall_SetAddress(Address addr);
/**
* Uses the given pointer value as function address for the SDK call.
*
* @param handle Handle to a MemoryPointer.
* @return True on success, false on failure.
* @error Invalid handle.
*/
native bool PrepSDKCall_SetAddressFromMemoryPointer(MemoryPointer handle);
/**
* Finds an address or virtual function index in a GameConfig file and sets it as
* the calling information for the SDK call.

View File

@ -113,13 +113,28 @@ methodmap GameData < Handle
//
// @param name Name of the property to find.
// @return An address calculated on success, or 0 on failure.
#pragma deprecated Use GameData.GetAddressEx instead
public native Address GetAddress(const char[] name);
// Finds an address calculation in a GameConfig file,
// performs LoadFromAddress on it as appropriate, then returns the final address as a new MemoryPointer handle.
//
// @param name Name of the property to find.
// @return New MemoryPointer handle containing the address calculated on success, or null on failure.
public native Address GetAddressEx(const char[] name);
// Returns a function address calculated from a signature.
//
// @param name Name of the property to find.
// @return An address calculated on success, or 0 on failure.
#pragma deprecated Use GameData.GetMemSigEx instead
public native Address GetMemSig(const char[] name);
// Returns a function address calculated from a signature as new MemoryPointer handle.
//
// @param name Name of the property to find.
// @return New MemoryPointer handle containing the address calculated on success, or null on failure.
public native Address GetMemSigEx(const char[] name);
};
/**
@ -467,6 +482,7 @@ native bool GameConfGetKeyValue(Handle gc, const char[] key, char[] buffer, int
* @param name Name of the property to find.
* @return An address calculated on success, or 0 on failure.
*/
#pragma deprecated Use GameData.GetAddressEx instead
native Address GameConfGetAddress(Handle gameconf, const char[] name);
/**
@ -739,6 +755,7 @@ enum Address
* @return The value that is stored at that address.
* @error Address is null or pointing to reserved memory.
*/
#pragma deprecated Use MemoryPointer.Load instead
native any LoadFromAddress(Address addr, NumberType size);
/**
@ -752,6 +769,7 @@ native any LoadFromAddress(Address addr, NumberType size);
* on the memory page being written to.
* @error Address is null or pointing to reserved memory.
*/
#pragma deprecated Use MemoryPointer.Store instead
native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true);
methodmap MemoryPointer < Handle {
@ -761,9 +779,11 @@ methodmap MemoryPointer < Handle {
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.
// @param data The data to store.
// @param size Size of the data to store.
// @param offset Offset in bytes from the start.
// @param updateMemAccess If true, SourceMod will set read / write / exec permissions
// on the memory page being written to.
public native void Store(any data, NumberType size, int offset = 0, bool updateMemAccess = true);
// Retrieves the data at the provided offset.
@ -771,6 +791,33 @@ methodmap MemoryPointer < Handle {
// @param offset Offset in bytes from the start.
// @return The data that was stored.
public native any Load(NumberType size, int offset = 0);
// Stores the given entity index into a CHandle at the provided offset.
// @param entity Entity index to store, -1 to clear.
// @param offset Offset in bytes from the start.
public native void StoreEntityToHandle(int entity, int offset = 0);
// Retrieves the entity index from the CHandle at the provided offset.
// @param offset Offset in bytes from the start.
// @return Entity index at the given location. If there is no entity, or the stored entity is invalid, then -1 is returned.
public native int LoadEntityFromHandle(int offset = 0);
// Stores a memory pointer at the provided offset.
// @param handle Handle to the memory pointer to store.
// @param offset Offset in bytes from the start.
// @param updateMemAccess If true, SourceMod will set read / write / exec permissions
// on the memory page being written to.
public native void StoreMemoryPointer(MemoryPointer handle, int offset = 0, bool updateMemAccess = true);
// Wraps the data loaded at the provided offset into a new MemoryPointer handle.
// @param offset Offset in bytes from the start.
// @return New Handle to a memory pointer.
public native MemoryPointer LoadMemoryPointer(int offset = 0);
// Creates a new MemoryPointer handle by offsetting the base pointer.
// @param size Offset from base pointer in bytes.
// @return New Handle to a memory pointer.
public native MemoryPointer Offset(int offset);
};
methodmap FrameIterator < Handle {

View File

@ -43,6 +43,11 @@ namespace SourceMod
public:
virtual ~IMemoryPointer() = default;
/**
* @brief Deletes the Memory pointer.
*/
virtual void Delete() = 0;
/**
* @brief Retrieves the underlying pointer.
*
@ -65,7 +70,7 @@ namespace SourceMod
* @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);
void Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess);
/**
* @brief Loads data at the given offset.
@ -74,9 +79,44 @@ namespace SourceMod
* @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);
cell_t Load(unsigned int byteSize, cell_t offset);
/**
* @brief Stores a pointer at the given offset.
*
* @param data The pointer to store.
* @param offset Offset in bytes to store the data at.
* @param updateMemAccess Whether or not to update the memory access before writing.
*/
void StorePtr(void* data, cell_t offset, bool updateMemAccess);
/**
* @brief Loads pointer at the given offset.
*
* @param offset Offset in bytes to read the data at.
* @return The pointer stored at the given offset.
*/
void* LoadPtr(cell_t offset);
};
inline void IMemoryPointer::StorePtr(void* data, cell_t offset, bool updateMemAccess)
{
auto ptr = &(((std::int8_t*)this->Get())[offset]);
if (updateMemAccess)
{
SourceHook::SetMemAccess(ptr, sizeof(void*), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
}
*(void**)ptr = data;
}
inline void* IMemoryPointer::LoadPtr(cell_t offset)
{
auto ptr = &(((std::int8_t*)this->Get())[offset]);
return *(void**)ptr;
}
inline void IMemoryPointer::Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess)
{
auto ptr = &(((std::int8_t*)this->Get())[offset]);