diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 06ae45a8..1c62e6fe 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1740,6 +1740,42 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_class(AMX* amx, cell* params) return 0; } +// cs_find_ent_by_owner(start_index, const classname[], owner) +static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) +{ + if (CS_UTIL_FindEntityByString <= 0) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_owner() is disabled"); + return 0; + } + + int owner = params[3]; + CHECK_ENTITY_SIMPLE(params[3]); + + int length; + void* pEntity = G_HL_TypeConversion.id_to_cbase(params[1]); + const char* value = MF_GetAmxString(amx, params[2], 0, &length); + + edict_t *pOwner = GETEDICT(owner); + + while ((pEntity = CS_UTIL_FindEntityByString(pEntity, "classname", value))) + { + edict_t *pev = G_HL_TypeConversion.cbase_to_edict(pEntity); + + if (!FNullEnt(pev) && pev->v.owner == pOwner) + { + int index = ENTINDEX(pev); + + if (index != -1) + { + return index; + }; + } + } + + return 0; +} + // native any:cs_get_item_id(const name[], &CsWeaponClassType:classid = CS_WEAPONCLASS_NONE); static cell AMX_NATIVE_CALL cs_get_item_id(AMX* amx, cell* params) { @@ -1926,6 +1962,7 @@ AMX_NATIVE_INFO CstrikeNatives[] = {"cs_set_c4_defusing", cs_set_c4_defusing}, {"cs_create_entity", cs_create_entity }, {"cs_find_ent_by_class", cs_find_ent_by_class}, + {"cs_find_ent_by_owner", cs_find_ent_by_owner}, {"cs_get_item_id", cs_get_item_id}, {"cs_get_translated_item_alias",cs_get_translated_item_alias}, {"cs_get_weapon_info", cs_get_weapon_info}, diff --git a/modules/cstrike/cstrike/CstrikeUtils.h b/modules/cstrike/cstrike/CstrikeUtils.h index ac94a113..f1a59c53 100644 --- a/modules/cstrike/cstrike/CstrikeUtils.h +++ b/modules/cstrike/cstrike/CstrikeUtils.h @@ -27,6 +27,17 @@ bool UTIL_CheckForPublic(const char *publicname); #define GETCLIENTKEYVALUE (*g_engfuncs.pfnInfoKeyValue) #define CREATENAMEDENTITY (*g_engfuncs.pfnCreateNamedEntity) +#define CHECK_ENTITY_SIMPLE(x) \ + if (x < 0 || x > gpGlobals->maxEntities) { \ + MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \ + return 0; \ + } else { \ + if (x != 0 && FNullEnt(INDEXENT(x))) { \ + MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \ + return 0; \ + } \ + } + #define CHECK_ENTITY(x) \ if (x < 0 || x > gpGlobals->maxEntities) { \ MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \ diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index b97d9400..d45fb904 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1025,6 +1025,26 @@ native cs_create_entity(const classname[]); */ native cs_find_ent_by_class(start_index, const classname[]); +/** + * Finds an entity in the world using Counter-Strike's custom FindEntityByString + * wrapper, matching by owner. + * + * @note Unlike other mods CS keeps track of entities using a custom hashtable. + * This function utilizes the hasthable and allows for considerably faster + * classname lookup compared to the default FindEntityByString (used by + * find_ent_by_owner() for example). + * @note This exclusively considers entities in the hashtable, created by the + * game itself or using cs_create_entity(). + * + * @param start_index Entity index to start searching from. -1 to start from + * the first entity + * @param classname Classname to search for + * @param owner Entity index to search for entity's owner + * + * @return Entity index > 0 if found, 0 otherwise + */ +native cs_find_ent_by_owner(start_index, const classname[], owner); + /** * Returns the item id associated with an item name and its aliases. *