Cache created entities by reference instead of index in SDKHooks (#634)

Fixes #663.
This commit is contained in:
Nicholas Hastings 2017-07-06 13:33:34 -04:00 committed by GitHub
parent fdac8a1677
commit 29d1187434
2 changed files with 42 additions and 22 deletions

View File

@ -103,8 +103,6 @@ SMEXT_LINK(&g_Interface);
CGlobalVars *gpGlobals; CGlobalVars *gpGlobals;
ke::Vector<CVTableList *> g_HookList[SDKHook_MAXHOOKS]; ke::Vector<CVTableList *> g_HookList[SDKHook_MAXHOOKS];
CBitVec<NUM_ENT_ENTRIES> m_EntityExists;
IBinTools *g_pBinTools = NULL; IBinTools *g_pBinTools = NULL;
ICvar *icvar = NULL; ICvar *icvar = NULL;
@ -231,6 +229,8 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
return false; return false;
} }
memset(m_EntityCache, INVALID_EHANDLE_INDEX, sizeof(m_EntityCache));
CUtlVector<IEntityListener *> *entListeners = EntListeners(); CUtlVector<IEntityListener *> *entListeners = EntListeners();
if (!entListeners) if (!entListeners)
{ {
@ -270,13 +270,20 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
continue; continue;
index = hndl.GetEntryIndex(); index = hndl.GetEntryIndex();
m_EntityExists.Set(index); if (IsEntityIndexInRange(index))
{
m_EntityCache[index] = gamehelpers->IndexToReference(index);
}
else
{
g_pSM->LogError(myself, "SDKHooks::HandleEntityCreated - Got entity index out of range (%d)", index);
}
} }
#else #else
for (int i = 0; i < NUM_ENT_ENTRIES; i++) for (int i = 0; i < NUM_ENT_ENTRIES; i++)
{ {
if (gamehelpers->ReferenceToEntity(i) != NULL) if (gamehelpers->ReferenceToEntity(i) != NULL)
m_EntityExists.Set(i); m_EntityCache[i] = gamehelpers->IndexToReference(i);
} }
#endif #endif
@ -411,14 +418,14 @@ void SDKHooks::OnClientPutInServer(int client)
{ {
CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client); CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
HandleEntityCreated(pPlayer, client); HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
} }
void SDKHooks::OnClientDisconnecting(int client) void SDKHooks::OnClientDisconnecting(int client)
{ {
CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client); CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client);
HandleEntityDeleted(pEntity, client); HandleEntityDeleted(pEntity);
} }
void SDKHooks::AddEntityListener(ISMEntityListener *listener) void SDKHooks::AddEntityListener(ISMEntityListener *listener)
@ -849,16 +856,26 @@ void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback)
void SDKHooks::OnEntityCreated(CBaseEntity *pEntity) void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
{ {
// Call OnEntityCreated forward // Call OnEntityCreated forward
int ref = gamehelpers->EntityToBCompatRef(pEntity); int ref = gamehelpers->EntityToReference(pEntity);
int index = gamehelpers->ReferenceToIndex(ref); int index = gamehelpers->ReferenceToIndex(ref);
// This can be -1 for player ents before any players have connected // This can be -1 for player ents before any players have connected
if ((unsigned)index == INVALID_EHANDLE_INDEX || m_EntityExists.IsBitSet(index) || (index > 0 && index <= playerhelpers->GetMaxClients())) if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
{ {
return; return;
} }
HandleEntityCreated(pEntity, ref); if (!IsEntityIndexInRange(index))
{
g_pSM->LogError(myself, "SDKHooks::OnEntityCreated - Got entity index out of range (%d)", index);
return;
}
// The entity could already exist. The creation notifier fires twice for some paths
if (m_EntityCache[index] != ref)
{
HandleEntityCreated(pEntity, index, ref);
}
} }
#ifdef GAMEDESC_CAN_CHANGE #ifdef GAMEDESC_CAN_CHANGE
@ -1633,8 +1650,7 @@ void SDKHooks::Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T
void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity) void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
{ {
int ref = gamehelpers->EntityToBCompatRef(pEntity); int index = gamehelpers->ReferenceToIndex(gamehelpers->EntityToReference(pEntity));
int index = gamehelpers->ReferenceToIndex(ref);
// This can be -1 for player ents before any players have connected // This can be -1 for player ents before any players have connected
if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients())) if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
@ -1642,7 +1658,7 @@ void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
return; return;
} }
HandleEntityDeleted(pEntity, ref); HandleEntityDeleted(pEntity);
} }
void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics) void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics)
@ -1752,9 +1768,10 @@ bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelin
RETURN_META_VALUE(MRES_IGNORED, true); RETURN_META_VALUE(MRES_IGNORED, true);
} }
void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int 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);
// Send OnEntityCreated to SM listeners // Send OnEntityCreated to SM listeners
SourceHook::List<ISMEntityListener *>::iterator iter; SourceHook::List<ISMEntityListener *>::iterator iter;
@ -1766,15 +1783,17 @@ void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int ref)
} }
// Call OnEntityCreated forward // Call OnEntityCreated forward
g_pOnEntityCreated->PushCell(ref); g_pOnEntityCreated->PushCell(bcompatRef);
g_pOnEntityCreated->PushString(pName ? pName : ""); g_pOnEntityCreated->PushString(pName ? pName : "");
g_pOnEntityCreated->Execute(NULL); g_pOnEntityCreated->Execute(NULL);
m_EntityExists.Set(gamehelpers->ReferenceToIndex(ref)); m_EntityCache[index] = ref;
} }
void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity, int ref) 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;
@ -1785,10 +1804,8 @@ void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity, int ref)
} }
// Call OnEntityDestroyed forward // Call OnEntityDestroyed forward
g_pOnEntityDestroyed->PushCell(ref); g_pOnEntityDestroyed->PushCell(bcompatRef);
g_pOnEntityDestroyed->Execute(NULL); g_pOnEntityDestroyed->Execute(NULL);
Unhook(pEntity); Unhook(pEntity);
m_EntityExists.Set(gamehelpers->ReferenceToIndex(ref), false);
} }

View File

@ -311,7 +311,6 @@ public:
void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr); void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr); void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
#endif #endif
void Hook_UpdateOnRemove();
void Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); void Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); void Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_VPhysicsUpdate(IPhysicsObject *pPhysics); void Hook_VPhysicsUpdate(IPhysicsObject *pPhysics);
@ -330,14 +329,18 @@ public:
bool Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex); bool Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex);
private: private:
void HandleEntityCreated(CBaseEntity *pEntity, int ref); void HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref);
void HandleEntityDeleted(CBaseEntity *pEntity, int ref); void HandleEntityDeleted(CBaseEntity *pEntity);
void Unhook(CBaseEntity *pEntity); void Unhook(CBaseEntity *pEntity);
void Unhook(IPluginContext *pContext); void Unhook(IPluginContext *pContext);
private: private:
int HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType); int HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType);
int HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType); int HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType);
private:
inline bool IsEntityIndexInRange(int i) { return i >= 0 && i < NUM_ENT_ENTRIES; }
cell_t m_EntityCache[NUM_ENT_ENTRIES];
}; };
extern CGlobalVars *gpGlobals; extern CGlobalVars *gpGlobals;