Skip to content

Commit

Permalink
Reconcile the concept of Edict & Networkable across the codebase (#1903)
Browse files Browse the repository at this point in the history
* Reconcile the concept of Edict & Networkable across the codebase

* There's no need to check this, it's done elsewhere. Also could be null (segfault)

* This was never needed

* Pseudo review changes

Re-added removed null checks, and added new ones.

Changed the error messages in Get/SetProp natives to better reflect reality.

* Don't change the behaviour of GetEntityNetClass

* Overload IGameHelpers::FindServerClass

* Make error messages more accurate

* Fix a dev comment

* Rename FindServerClass

---------

Co-authored-by: Kenzzer <[email protected]>
  • Loading branch information
Kenzzer and Kenzzer committed Jun 1, 2024
1 parent 9f3584a commit 7df2f8e
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 114 deletions.
11 changes: 11 additions & 0 deletions core/HalfLife2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,17 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
return pInfo->sc;
}

ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity)
{
IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable();
if (pNetwork == nullptr)
{
return nullptr;
}

return pNetwork->GetServerClass();
}

DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
{
DataTableInfo *pInfo = NULL;
Expand Down
1 change: 1 addition & 0 deletions core/HalfLife2.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class CHalfLife2 :
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname);
ServerClass *FindEntityServerClass(CBaseEntity *pEntity);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
Expand Down
52 changes: 23 additions & 29 deletions core/smn_entities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,10 @@ inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
{
IServerUnknown *pUnk = (IServerUnknown *)pEntity;
IServerNetworkable *pNet = pUnk->GetNetworkable();

if (!pNet)
if (pNet == nullptr)
{
return NULL;
return nullptr;
}

return pNet->GetEdict();
}

Expand Down Expand Up @@ -363,14 +361,20 @@ static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)

static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
{
edict_t *pEdict = GetEdict(params[1]);
IServerUnknown *pUnknown = (IServerUnknown *)g_HL2.ReferenceToEntity(params[1]);
if (!pUnknown)
{
return 0;
}

if (!pEdict)
IServerNetworkable *pNet = pUnknown->GetNetworkable();
if (!pNet)
{
return 0;
}

return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
edict_t* edict = pNet->GetEdict();
return (edict && !edict->IsFree()) ? 1 : 0;
}

static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
Expand Down Expand Up @@ -436,14 +440,12 @@ static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
}

IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
ServerClass *pClass = g_HL2.FindEntityServerClass(pEntity);
if (!pClass)
{
return 0;
}

ServerClass *pClass = pNet->GetServerClass();

pContext->StringToLocal(params[2], params[3], pClass->GetName());

return 1;
Expand Down Expand Up @@ -1270,13 +1272,11 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
#define FIND_PROP_SEND(type, type_name) \
sm_sendprop_info_t info;\
SendProp *pProp; \
IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
IServerNetworkable *pNet = pUnk->GetNetworkable(); \
if (!pNet) \
{ \
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity); \
if (pServerClass == nullptr) { \
pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]); \
} \
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \
if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info)) \
{ \
const char *class_name = g_HL2.GetEntityClassname(pEntity); \
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
Expand Down Expand Up @@ -1434,13 +1434,13 @@ static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params
{
sm_sendprop_info_t info;

IServerUnknown *pUnk = (IServerUnknown *)pEntity;
IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity);
if (pServerClass == nullptr)
{
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]);
return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))

if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info))
{
const char *class_name = g_HL2.GetEntityClassname(pEntity);
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)",
Expand Down Expand Up @@ -2079,13 +2079,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
edict_t *pOtherEdict = NULL;
if (pOther)
{
IServerNetworkable *pNetworkable = ((IServerUnknown *) pOther)->GetNetworkable();
if (!pNetworkable)
{
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
}

pOtherEdict = pNetworkable->GetEdict();
pOtherEdict = BaseEntityToEdict(pOther);
if (!pOtherEdict || pOtherEdict->IsFree())
{
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
Expand Down
9 changes: 6 additions & 3 deletions extensions/cstrike/natives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,13 @@ static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params)

//Psychonic is awesome for this
sm_sendprop_info_t spi;
IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
IServerNetworkable *pNet = pUnk->GetNetworkable();
ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pWeapon);
if (pServerClass == nullptr)
{
return pContext->ThrowNativeError("Failed to retrieve entity %d server class!", params[2]);
}

if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", &spi, 0))
if (!UTIL_FindDataTable(pServerClass->m_pTable, "DT_WeaponCSBase", &spi, 0))
return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);

if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", &spi))
Expand Down
11 changes: 8 additions & 3 deletions extensions/sdkhooks/extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,11 +614,16 @@ HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callbac

if (!!strcmp(g_HookTypes[type].dtReq, ""))
{
IServerUnknown *pUnk = (IServerUnknown *)pEnt;
ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEnt);
if (pServerClass == nullptr)
{
return HookRet_BadEntForHookType;
}

IServerNetworkable *pNet = pUnk->GetNetworkable();
if (pNet && !UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq))
if (!UTIL_ContainsDataTable(pServerClass->m_pTable, g_HookTypes[type].dtReq))
{
return HookRet_BadEntForHookType;
}
}

size_t entry;
Expand Down
41 changes: 22 additions & 19 deletions extensions/sdkhooks/natives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ cell_t Native_Hook(IPluginContext *pContext, const cell_t *params)
break;
case HookRet_BadEntForHookType:
{
CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(params[1]);
const char *pClassname = pEnt ? gamehelpers->GetEntityClassname(pEnt) : NULL;
if (!pClassname)
{
pContext->ThrowNativeError("Hook type not valid for this type of entity (%i).", entity);
}
else
{
pContext->ThrowNativeError("Hook type not valid for this type of entity (%i/%s)", entity, pClassname);
CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(params[1]);
const char *pClassname = pEnt ? gamehelpers->GetEntityClassname(pEnt) : NULL;
if (!pClassname)
{
pContext->ThrowNativeError("Hook type not valid for this type of entity (%i).", entity);
}
else
{
pContext->ThrowNativeError("Hook type not valid for this type of entity (%i/%s)", entity, pClassname);
}

break;
Expand Down Expand Up @@ -185,9 +185,9 @@ cell_t Native_TakeDamage(IPluginContext *pContext, const cell_t *params)
if (!pCall)
{
int offset;
if (!g_pGameConf->GetOffset("OnTakeDamage", &offset))
{
return pContext->ThrowNativeError("Could not find OnTakeDamage offset");
if (!g_pGameConf->GetOffset("OnTakeDamage", &offset))
{
return pContext->ThrowNativeError("Could not find OnTakeDamage offset");
}

PassInfo pass[2];
Expand Down Expand Up @@ -230,10 +230,13 @@ cell_t Native_DropWeapon(IPluginContext *pContext, const cell_t *params)
if (!pWeapon)
return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);

IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
IServerNetworkable *pNet = pUnk->GetNetworkable();

if (!UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, "DT_BaseCombatWeapon"))
ServerClass *pClass = gamehelpers->FindEntityServerClass(pWeapon);
if (pClass == nullptr)
{
return pContext->ThrowNativeError("Failed to retrieve entity %d server class!", params[2]);
}

if (!UTIL_ContainsDataTable(pClass->m_pTable, "DT_BaseCombatWeapon"))
return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);

sm_sendprop_info_t spi;
Expand Down Expand Up @@ -291,9 +294,9 @@ cell_t Native_DropWeapon(IPluginContext *pContext, const cell_t *params)
if (!pCall)
{
int offset;
if (!g_pGameConf->GetOffset("Weapon_Drop", &offset))
{
return pContext->ThrowNativeError("Could not find Weapon_Drop offset");
if (!g_pGameConf->GetOffset("Weapon_Drop", &offset))
{
return pContext->ThrowNativeError("Could not find Weapon_Drop offset");
}

PassInfo pass[3];
Expand Down
27 changes: 14 additions & 13 deletions extensions/sdktools/gamerulesnatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,27 @@ static CBaseEntity *FindEntityByNetClass(int start, const char *classname)
int maxEntities = gpGlobals->maxEntities;
for (int i = start; i < maxEntities; i++)
{
edict_t *current = gamehelpers->EdictOfIndex(i);
if (current == NULL || current->IsFree())
continue;

IServerNetworkable *network = current->GetNetworkable();
if (network == NULL)
CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
if (pEntity == nullptr)
{
continue;
}

IHandleEntity *pHandleEnt = network->GetEntityHandle();
if (pHandleEnt == NULL)
ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEntity);
if (pServerClass == nullptr)
{
continue;
}


ServerClass *sClass = network->GetServerClass();
const char *name = sClass->GetName();

const char *name = pServerClass->GetName();
if (!strcmp(name, classname))
return gamehelpers->ReferenceToEntity(gamehelpers->IndexOfEdict(current));
{
return pEntity;
}
}

return NULL;
return nullptr;
}

static CBaseEntity* GetGameRulesProxyEnt()
Expand Down
18 changes: 9 additions & 9 deletions extensions/sdktools/teamnatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,35 @@ void InitTeamNatives()

int edictCount = gpGlobals->maxEntities;

for (int i=0; i<edictCount; i++)
for (int i = 0; i < edictCount; i++)
{
edict_t *pEdict = PEntityOfEntIndex(i);
if (!pEdict || pEdict->IsFree())
CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
if (pEntity == nullptr)
{
continue;
}
if (!pEdict->GetNetworkable())

ServerClass *pClass = gamehelpers->FindEntityServerClass(pEntity);
if (pClass == nullptr)
{
continue;
}

ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass();

if (FindNestedDataTable(pClass->m_pTable, "DT_Team"))
{
SendProp *pTeamNumProp = g_pGameHelpers->FindInSendTable(pClass->GetName(), "m_iTeamNum");

if (pTeamNumProp != NULL)
{
int offset = pTeamNumProp->GetOffset();
CBaseEntity *pEnt = pEdict->GetUnknown()->GetBaseEntity();
int TeamIndex = *(int *)((unsigned char *)pEnt + offset);
int TeamIndex = *(int *)((unsigned char *)pEntity + offset);

if (TeamIndex >= (int)g_Teams.size())
{
g_Teams.resize(TeamIndex+1);
}
g_Teams[TeamIndex].ClassName = pClass->GetName();
g_Teams[TeamIndex].pEnt = pEnt;
g_Teams[TeamIndex].pEnt = pEntity;
}
}
}
Expand Down
19 changes: 7 additions & 12 deletions extensions/sdktools/vglobals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,28 +321,23 @@ void GetResourceEntity()
{
int edictCount = gpGlobals->maxEntities;

for (int i=0; i<edictCount; i++)
for (int i = 0; i < edictCount; i++)
{
edict_t *pEdict = PEntityOfEntIndex(i);
if (!pEdict || pEdict->IsFree())
{
continue;
}
if (!pEdict->GetNetworkable())
CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
if (pEntity == nullptr)
{
continue;
}

IHandleEntity *pHandleEnt = pEdict->GetNetworkable()->GetEntityHandle();
if (!pHandleEnt)
ServerClass *pClass = gamehelpers->FindEntityServerClass(pEntity);
if (pClass == nullptr)
{
continue;
}

ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass();

if (FindNestedDataTable(pClass->m_pTable, "DT_PlayerResource"))
{
g_ResourceEntity = pHandleEnt->GetRefEHandle();
g_ResourceEntity = ((IHandleEntity *)pEntity)->GetRefEHandle();
break;
}
}
Expand Down
14 changes: 12 additions & 2 deletions extensions/sdktools/vnatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1689,7 +1689,12 @@ static cell_t LookupEntityAttachment(IPluginContext* pContext, const cell_t* par
CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
ServerClass* pClass = gamehelpers->FindEntityServerClass(pEntity);
if (pClass == nullptr)
{
return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", gamehelpers->ReferenceToIndex(params[1]), params[1]);
}

if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
{
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]);
Expand Down Expand Up @@ -1735,7 +1740,12 @@ static cell_t GetEntityAttachment(IPluginContext* pContext, const cell_t* params
CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
ServerClass* pClass = gamehelpers->FindEntityServerClass(pEntity);
if (pClass == nullptr)
{
return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", gamehelpers->ReferenceToIndex(params[1]), params[1]);
}

if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
{
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]);
Expand Down
Loading

0 comments on commit 7df2f8e

Please sign in to comment.