From 083ab81035de23d62399db90ef27344fe4b543e8 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sun, 7 Jan 2018 13:52:36 -0500 Subject: [PATCH] Add RemoveEntity native. (bug 5714) (#745) --- core/smn_entities.cpp | 52 ++++++++++++++++++++++++++++++++++++++ plugins/include/entity.inc | 8 ++++++ 2 files changed, 60 insertions(+) diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 71fed68e..82311f77 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -94,6 +94,7 @@ enum PropFieldType PropField_Variant, /**< Valid for variants/any. (User must know type) */ }; +// From game/server/variant_t.h, same on all supported games. class variant_t { public: @@ -111,6 +112,15 @@ public: fieldtype_t fieldType; }; +// From game/server/baseentity.h, same on all supported games. +struct inputdata_t +{ + CBaseEntity *pActivator; // The entity that initially caused this chain of output events. + CBaseEntity *pCaller; // The entity that fired this particular output. + variant_t value; // The data parameter for this output. + int nOutputID; // The unique ID of the output that was fired. +}; + inline bool CanSetPropName(const char *pszPropName) { #if SOURCE_ENGINE == SE_CSGO @@ -280,6 +290,47 @@ static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t RemoveEntity(IPluginContext *pContext, const cell_t *params) +{ + auto *pEntity = GetEntity(params[1]); + if (!pEntity) + { + return pContext->ThrowNativeError("Entity %d (%d) is not a valid entity", g_HL2.ReferenceToIndex(params[1]), params[1]); + } + + // Some games have UTIL_Remove exposed on IServerTools, but for consistence, we'll + // use this method for all. Results in DeathNotice( this ) being called on parent, + // and parent being cleared (both if any parent) before UTIL_Remove is called. + static inputfunc_t fnKillEntity = nullptr; + if (!fnKillEntity) + { + // Get world, as other ents aren't guaranteed to inherit full datadesc (but kill func is same for all) + CBaseEntity *pGetterEnt = g_HL2.ReferenceToEntity(0); + if (pGetterEnt == nullptr) + { + // If we don't have a world entity yet, we'll have to rely on the given entity. Does this even make sense??? + pGetterEnt = pEntity; + } + + datamap_t *pMap = g_HL2.GetDataMap(pGetterEnt); + + sm_datatable_info_t info; + if (!g_HL2.FindDataMapInfo(pMap, "InputKill", &info)) + { + return pContext->ThrowNativeError("Failed to find Kill input!"); + } + + fnKillEntity = info.prop->inputFunc; + } + + // Input data is ignored for this. No need to initialize + static inputdata_t data; + + (pEntity->*fnKillEntity)(data); + + return 1; +} + static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params) { edict_t *pEdict = GetEdict(params[1]); @@ -2640,6 +2691,7 @@ REGISTER_NATIVES(entityNatives) {"IsEntNetworkable", IsEntNetworkable}, {"IsValidEdict", IsValidEdict}, {"IsValidEntity", IsValidEntity}, + {"RemoveEntity", RemoveEntity}, {"RemoveEdict", RemoveEdict}, {"SetEdictFlags", SetEdictFlags}, {"SetEntData", SetEntData}, diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 840f2dac..fba1e803 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -142,6 +142,14 @@ native int CreateEdict(); */ native void RemoveEdict(int edict); +/** + * Marks an entity for deletion. + * + * @param entity Index of the entity. + * @error Invalid entity index. + */ +native void RemoveEntity(int entity); + /** * Returns the flags on an edict. These are not the same as entity flags. *