From 2130c60fd9b8750a7a9a9a8e796d88110af61329 Mon Sep 17 00:00:00 2001 From: nosoop Date: Wed, 28 Dec 2022 19:57:47 -0800 Subject: [PATCH] Implement raw entity handle accessors (#1830) * Implement raw entity handle accessors * Fix FromPseudoAddress calls on 64-bit * fixup: Remove unnecessary ent deref * fixup: Correct param index in thrown error --- core/smn_entities.cpp | 70 ++++++++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 16 +++++++++ 2 files changed, 86 insertions(+) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 7e233b945..139da9cc1 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -706,6 +706,36 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params) return g_HL2.EntityToBCompatRef(pHandleEntity); } +//memory addresses below 0x10000 are automatically considered invalid for dereferencing +//this is copied over from smn_core.cpp +#define VALID_MINIMUM_MEMORY_ADDRESS 0x10000 + +static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params) +{ +#ifdef PLATFORM_X86 + void *addr = reinterpret_cast(params[1]); +#else + void *addr = g_SourceMod.FromPseudoAddress(params[1]); +#endif + + if (addr == NULL) + { + return pContext->ThrowNativeError("Address cannot be null"); + } + else if (reinterpret_cast(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + + CBaseHandle &hndl = *reinterpret_cast(addr); + CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex()); + + if (!pHandleEntity || hndl != reinterpret_cast(pHandleEntity)->GetRefEHandle()) + return -1; + + return g_HL2.EntityToBCompatRef(pHandleEntity); +} + /* THIS GUY IS DEPRECATED. */ static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params) { @@ -791,6 +821,44 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params) +{ +#ifdef PLATFORM_X86 + void *addr = reinterpret_cast(params[1]); +#else + void *addr = g_SourceMod.FromPseudoAddress(params[1]); +#endif + + if (addr == NULL) + { + return pContext->ThrowNativeError("Address cannot be null"); + } + else if (reinterpret_cast(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + + CBaseHandle &hndl = *reinterpret_cast(addr); + + if ((unsigned)params[2] == INVALID_EHANDLE_INDEX) + { + hndl.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; + hndl.Set(pHandleEnt); + } + return 1; +} + static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params) { edict_t *pEdict = GetEdict(params[1]); @@ -2752,5 +2820,7 @@ REGISTER_NATIVES(entityNatives) {"SetEntPropVector", SetEntPropVector}, {"GetEntityAddress", GetEntityAddress}, {"FindDataMapInfo", FindDataMapInfo}, + {"LoadEntityFromHandleAddress", LoadEntityFromHandleAddress}, + {"StoreEntityToHandleAddress", StoreEntityToHandleAddress}, {NULL, NULL} }; diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index ba13c6e2e..0bebb6a1a 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -767,3 +767,19 @@ stock bool GetEntityClassname(int entity, char[] clsname, int maxlength) { return !!GetEntPropString(entity, Prop_Data, "m_iClassname", clsname, maxlength); } + +/** + * Interprets the address as an entity handle and returns the associated entity. + * + * @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. + */ +native int LoadEntityFromHandleAddress(Address addr); + +/** + * Interprets the address as an entity handle and sets the entity. + * + * @param addr Address to a memory location. + * @param entity Entity index to set, or -1 to clear. + */ +native void StoreEntityToHandleAddress(Address addr, int entity);