sdkhooks: add OnEntitySpawned fwd. (#1078)

* Add OnEntitySpawned to SDKHooks.

* nitpicking

* Add CapabilityProvider SDKHook_OnEntitySpawned

* (unrelated) nits

* nit relocation

* unqualified relocation - my mistake.

Co-authored-by: Kyle Sanderson <kyle.leet@gmail.com>
This commit is contained in:
BotoX 2020-08-07 05:01:07 +02:00 committed by GitHub
parent 510bd261f8
commit 7bab9cc344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 11 deletions

View File

@ -112,6 +112,7 @@ IServerTools *servertools = NULL;
// global hooks and forwards // global hooks and forwards
IForward *g_pOnEntityCreated = NULL; IForward *g_pOnEntityCreated = NULL;
IForward *g_pOnEntitySpawned = NULL;
IForward *g_pOnEntityDestroyed = NULL; IForward *g_pOnEntityDestroyed = NULL;
#ifdef GAMEDESC_CAN_CHANGE #ifdef GAMEDESC_CAN_CHANGE
@ -246,12 +247,14 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
sharesys->AddInterface(myself, &g_Interface); sharesys->AddInterface(myself, &g_Interface);
sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD"); sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport"); sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
sharesys->AddCapabilityProvider(myself, this, "SDKHook_OnEntitySpawned");
playerhelpers->AddClientListener(&g_Interface); playerhelpers->AddClientListener(&g_Interface);
plsys->AddPluginsListener(&g_Interface); plsys->AddPluginsListener(&g_Interface);
g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String); g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
g_pOnEntitySpawned = forwards->CreateForward("OnEntitySpawned", ET_Ignore, 2, NULL, Param_Cell, Param_String);
g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell); g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
#ifdef GAMEDESC_CAN_CHANGE #ifdef GAMEDESC_CAN_CHANGE
g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String); g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
@ -344,6 +347,7 @@ void SDKHooks::SDK_OnUnload()
#endif #endif
forwards->ReleaseForward(g_pOnEntityCreated); forwards->ReleaseForward(g_pOnEntityCreated);
forwards->ReleaseForward(g_pOnEntitySpawned);
forwards->ReleaseForward(g_pOnEntityDestroyed); forwards->ReleaseForward(g_pOnEntityDestroyed);
#ifdef GAMEDESC_CAN_CHANGE #ifdef GAMEDESC_CAN_CHANGE
forwards->ReleaseForward(g_pOnGetGameNameDescription); forwards->ReleaseForward(g_pOnGetGameNameDescription);
@ -356,6 +360,7 @@ void SDKHooks::SDK_OnUnload()
sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD"); sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport"); sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
sharesys->DropCapabilityProvider(myself, this, "SDKHook_OnEntitySpawned");
CUtlVector<IEntityListener *> *entListeners = EntListeners(); CUtlVector<IEntityListener *> *entListeners = EntListeners();
entListeners->FindAndRemove(this); entListeners->FindAndRemove(this);
@ -420,6 +425,7 @@ void SDKHooks::OnClientPutInServer(int client)
CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client); CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer)); HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
HandleEntitySpawned(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
} }
void SDKHooks::OnClientDisconnecting(int client) void SDKHooks::OnClientDisconnecting(int client)
@ -885,6 +891,27 @@ void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
} }
} }
void SDKHooks::OnEntitySpawned(CBaseEntity *pEntity)
{
// Call OnEntitySpawned forward
int ref = gamehelpers->EntityToReference(pEntity);
int index = gamehelpers->ReferenceToIndex(ref);
// This can be -1 for player ents before any players have connected
if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
{
return;
}
if (!IsEntityIndexInRange(index))
{
g_pSM->LogError(myself, "SDKHooks::OnEntitySpawned - Got entity index out of range (%d)", index);
return;
}
HandleEntitySpawned(pEntity, index, ref);
}
#ifdef GAMEDESC_CAN_CHANGE #ifdef GAMEDESC_CAN_CHANGE
const char *SDKHooks::Hook_GetGameDescription() const char *SDKHooks::Hook_GetGameDescription()
{ {
@ -1778,29 +1805,58 @@ bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelin
void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref) void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref)
{ {
const char *pName = gamehelpers->GetEntityClassname(pEntity); const char *pName = gamehelpers->GetEntityClassname(pEntity);
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity); if (!pName)
pName = "";
// Send OnEntityCreated to SM listeners // Send OnEntityCreated to SM listeners
SourceHook::List<ISMEntityListener *>::iterator iter; SourceHook::List<ISMEntityListener *>::iterator iter;
ISMEntityListener *pListener = NULL; ISMEntityListener *pListener = NULL;
for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++) for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
{ {
pListener = (*iter); pListener = (*iter);
pListener->OnEntityCreated(pEntity, pName ? pName : ""); pListener->OnEntityCreated(pEntity, pName);
} }
// Call OnEntityCreated forward // Call OnEntityCreated forward
g_pOnEntityCreated->PushCell(bcompatRef); if (g_pOnEntityCreated->GetFunctionCount())
g_pOnEntityCreated->PushString(pName ? pName : ""); {
g_pOnEntityCreated->Execute(NULL); cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
g_pOnEntityCreated->PushCell(bcompatRef);
g_pOnEntityCreated->PushString(pName);
g_pOnEntityCreated->Execute(NULL);
}
m_EntityCache[index] = ref; m_EntityCache[index] = ref;
} }
void SDKHooks::HandleEntitySpawned(CBaseEntity *pEntity, int index, cell_t ref)
{
if (g_pOnEntitySpawned->GetFunctionCount() || m_EntListeners.size())
{
const char *pName = gamehelpers->GetEntityClassname(pEntity);
if (!pName)
pName = "";
// Send OnEntitySpawned to SM listeners
for (SourceHook::List<ISMEntityListener *>::iterator iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
{
ISMEntityListener *pListener = (*iter);
pListener->OnEntitySpawned(pEntity, pName);
}
// Call OnEntitySpawned forward
if (g_pOnEntitySpawned->GetFunctionCount())
{
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
g_pOnEntitySpawned->PushCell(bcompatRef);
g_pOnEntitySpawned->PushString(pName);
g_pOnEntitySpawned->Execute(NULL);
}
}
}
void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity) void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity)
{ {
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
// Send OnEntityDestroyed to SM listeners // Send OnEntityDestroyed to SM listeners
SourceHook::List<ISMEntityListener *>::iterator iter; SourceHook::List<ISMEntityListener *>::iterator iter;
ISMEntityListener *pListener = NULL; ISMEntityListener *pListener = NULL;
@ -1811,8 +1867,12 @@ void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity)
} }
// Call OnEntityDestroyed forward // Call OnEntityDestroyed forward
g_pOnEntityDestroyed->PushCell(bcompatRef); if (g_pOnEntityDestroyed->GetFunctionCount())
g_pOnEntityDestroyed->Execute(NULL); {
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
g_pOnEntityDestroyed->PushCell(bcompatRef);
g_pOnEntityDestroyed->Execute(NULL);
}
Unhook(pEntity); Unhook(pEntity);
} }

View File

@ -238,6 +238,7 @@ public: // IFeatureProvider
public: // IEntityListener public: // IEntityListener
virtual void OnEntityCreated(CBaseEntity *pEntity); virtual void OnEntityCreated(CBaseEntity *pEntity);
virtual void OnEntitySpawned(CBaseEntity *pEntity);
virtual void OnEntityDeleted(CBaseEntity *pEntity); virtual void OnEntityDeleted(CBaseEntity *pEntity);
public: // IClientListener public: // IClientListener
@ -330,6 +331,7 @@ public:
private: private:
void HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref); void HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref);
void HandleEntitySpawned(CBaseEntity *pEntity, int index, cell_t ref);
void HandleEntityDeleted(CBaseEntity *pEntity); void HandleEntityDeleted(CBaseEntity *pEntity);
void Unhook(CBaseEntity *pEntity); void Unhook(CBaseEntity *pEntity);
void Unhook(IPluginContext *pContext); void Unhook(IPluginContext *pContext);

View File

@ -347,6 +347,16 @@ typeset SDKHookCB
*/ */
forward void OnEntityCreated(int entity, const char[] classname); forward void OnEntityCreated(int entity, const char[] classname);
/**
* When an entity is spawned
*
* @param entity Entity index
* @param classname Class name
*
* @note Check for support at runtime using GetFeatureStatus on SDKHook_OnEntitySpawned capability.
*/
forward void OnEntitySpawned(int entity, const char[] classname);
/** /**
* When an entity is destroyed * When an entity is destroyed
* *

View File

@ -36,7 +36,7 @@
#include <IShareSys.h> #include <IShareSys.h>
#define SMINTERFACE_SDKHOOKS_NAME "ISDKHooks" #define SMINTERFACE_SDKHOOKS_NAME "ISDKHooks"
#define SMINTERFACE_SDKHOOKS_VERSION 1 #define SMINTERFACE_SDKHOOKS_VERSION 2
class CBaseEntity; class CBaseEntity;
@ -71,6 +71,16 @@ namespace SourceMod
virtual void OnEntityDestroyed(CBaseEntity *pEntity) virtual void OnEntityDestroyed(CBaseEntity *pEntity)
{ {
} }
/**
* @brief When an entity is spawned
*
* @param pEntity CBaseEntity entity.
* @param classname Entity classname.
*/
virtual void OnEntitySpawned(CBaseEntity *pEntity, const char *classname)
{
}
}; };
/** /**