AI Entities - zeroKilo/GROBackendWV GitHub Wiki
Overview
In AI.dll, entities are all the objects that can be created via network. The most important are AI_EntityPlayer
- player object, and AI_EntityPlayerAbstract
- player abstraction object.
All the AI_EntityPlayer
objects must have corresponding abstract player objects.
AI_EntityPlayerAbstract
is also used as a highest-level server instance, created on the server, then serialized, sent and updated to all the player clients (see cObjectManager::InitEntityAndReplicate
). There each local copy of the server's abstract player entity controls local events like explosions, ability usage etc.
Inheritance
Entities inherit from one another. As mentioned above, the most important are AI_EntityPlayer
and AI_EntityPlayerAbstract
. If an entity receives replicated data, the fields are listed as a sublist. The inheritance paths are (every lower class extends the upper):
AI_EntityPlayer
AI_BaseGAO
- base class with core game object (GAO) fields, not considered an entityAI_Entity
- base entity class, has its own handle and serialization flagsAI_EntityConcrete
- extension for some other entity objects, not really importantAI_EntityDynamic
- adds health object and base player fields like team and soldier class IDsAI_EntityPawn
- adds physics handling and a part of player's inventory managementm_ReplicatedPosition
(3D float vector)m_ReplicatedAngle
(2D float vector)m_CritSalt
(uint)m_CritRandSeed
(uint)m_ShootPosition
(3D float vector)m_ShootTargetHandle
(uint)m_WhistlingBullet
(byte)m_Rush
(byte)m_PlayerFire
(2x byte)m_CurrentWeaponSlot
(byte)m_WantedWeaponSlot
(byte)m_OldWeaponSlot
(byte)
AI_EntityHuman
- adds animation handling, stances, cover interactions, more inventory managementm_ReplicatedCamPitch
(2x float)m_GoToPosition
(3D float vector)m_MoveMode
(byte)m_FocusedEntityReplication
(byte)m_CoverHeight
(float)m_CoverFlagWanted
(short)m_CoverNormal
(3D float vector)m_State
(byte)m_StateServer
(byte)m_LaserSightStateCurr
(byte)m_SlideVelocity
(float)m_SlideToRosaceAnim
(byte)m_BlitzShieldArmed
(byte)m_OrderStatus
(byte)m_FireModeType
(byte)m_RollAnimIndex
(byte)m_ReplicatedPowerPC
(byte + float)m_CurrentEnergyPC
(float)m_KikooMoveCount
(short)m_Mood
(uint)m_HitPart
(byte)m_LeftHandSide
(byte)
AI_EntityPlayer
- final player object, holds weapon objectsm_bHealthRegenActive
(byte)
AI_EntityPlayerAbstract
AI_Entity
AI_EntityService
- not importantAI_EntityPlayerAbstract
- final player abstraction objectm_DeathCount
(uint)m_AbilityInventoryId
(uint)m_PassiveAbilityInventoryId
(uint)m_DesiredWeaponIds
(4x uint)m_AchievementPoints
(uint)m_HelmetInventoryId
(uint)m_ArmorTierInventoryId
(uint)m_SpawnBlockingReasons
(short)m_Class
(byte)m_ClassLevel
(short)m_PortraitId
(uint)m_PersonaName
(string)
Class IDs
Entities have internal IDs referred to as 'class'. They are used to create entity handles. The IDs are:
- 1 -
AI_Entity
- 2 -
AI_EntityService
- 3 -
AI_EntityConcrete
- 4 -
AI_EntityDynamic
- 10 -
AI_EntityPawn
- 11 -
AI_EntityHuman
- 31 -
AI_EntityPlayer
- 33 -
AI_EntityPlayerAbstract
Handles
Entity handles allow referencing a particular entity. Here's how server entity handle is generated:
_DWORD *__cdecl AI_EntityPlayerAbstract::ds_GetDSHandle(_DWORD *handle, AI_EntityPlayerAbstract *entity)
{
cEntityManager *entMan; // eax
int maxHandle; // esi
*handle = 0;
if ( cEntityManager::Instance )
{
entMan = cEntityManager::Get();
maxHandle = entMan->nextNewHandle;
entMan->nextNewHandle = maxHandle + 1;
handle = (maxHandle + ((entity->pVMT->AI_EntityPlayerAbstract::GetEntityClassId)() << 24));// get 31 for entityPlayer or 33 for abstract; 33 << 24 = 0x21000000
hEntity::GetHandle(handle, &handle);
}
return handle;
}
Since entity class IDs are used to generate a handle, it allows entity class identification as shown below (from cObjectManager::BroadcastMessage
):
entity = ((*ptr_DLLEngine.vmt)->ptr_yeti_sub_416F00__CreateEntityObject)(obj, "AI_Entity");
if ( entity )
{
className = (entity->pVMT->AI_EntityPlayer::GetClassName)(entity, handle);
DBG_SendSessionLog(
0,
"cObjectManager::BroadcastMessage ( 268 ) ",
"Object Created [Owner=0x%x, Class=%s, Object Handle=0x%x]",
Owner,
className);
AI_EntityPlayer::SetMasterFlag(entity, Owner);
v11 = dynamicBankId;
LoadFrom = entity->pVMT->AI_EntityPlayer::LoadFrom;
entity->bankIndex = dynamicBankElementId;
entity->bankId = v11;
(LoadFrom)(entity, &v29 + 1); // deserialization
AI_EntityPlayer::CallInitEntityAbstractOrPlayer(entity, st7_0, 0);// init deserialized entity
}
Typical handle validation looks like this:
bool __cdecl cEntityManager::ValidHandle(unsigned int handle)
{
unsigned int handleRsh; // esi
bool isValid; // bl
if ( !cEntityManager::Instance || !AI_NetworkManager::Instance )
return 1;
if ( handle )
{
handleRsh = handle >> 24;
if ( AI_NetworkManager::IsServer() )
{
if ( (handle & 0xFFFFFF) < cEntityManager::Get()->nextNewHandle && handleRsh < 102 )
return 1;
isValid = 0;
}
else // client
{
isValid = handleRsh < 102;
if ( handleRsh < 102 )
return isValid;
}
dword_102E8610 = rev_SendErrorMessage(
dword_102E8610 != 1,
"..\\SRC\\Entity\\cEntityManager.cpp",
"cEntityManager::ValidHandle",
212,
"cEntityManager::ValidHandle invalid handle. Please crash");
if ( dword_102E8610 == 3 )
__debugbreak();
return isValid;
}
return 1;
}
Serialization flags
Serialization flags is a working name for 0x30 entity uint that holds flags indicating entity's network role, which is core for proper replication and duplicated objects handling. First 6 bits are used:
- Bit 1
- set: master entity (local player)
- unset: duplica/replica entity
- Bit 2
- set: server entity
- unset: client entity
- Bit 4
- set: entity is registered by
cEntityManager
- unset: entity was not registered by
cEntityManager
- set: entity is registered by
- Bit 8
- set: entity is initialized
- unset: entity is not initialized
- Bit 16
- set: not seen used
- unset: not seen used
- Bit 32
- set: fire Brain event
- unset: set Brain flag
Other objects
There are other objects that inherit from AI_Entity
:
AI_DynObject
AI_EntityDedicatedSpy