using System.Collections.Generic; using UAI; using UnityEngine; /// /// Populated exactly once at the top of EntityAliveSDXV4.OnUpdateLive and passed by /// reference to every component. Ensures that expensive world/entity lookups such as /// GetLeaderOrOwner and GetAttackOrRevengeTarget happen only once per tick regardless of /// how many components or methods need that data. /// public struct NPCFrameCache { /// The entity's current leader/owner, or null. public EntityAlive Leader; /// Leader cast to EntityPlayer, or null when the leader is not a player. public EntityPlayer LeaderAsPlayer; /// Pre-calculated distance to the leader. Zero when there is no leader. public float DistanceToLeader; /// /// Squared distance to the leader (no sqrt cost). Use for comparisons where the /// exact distance is not needed — e.g. if (cache.DistanceSqToLeader > threshold * threshold). /// Zero when there is no leader. /// public float DistanceSqToLeader; /// True when a leader exists. public bool HasLeader; /// True when the leader is the local player on this machine. public bool IsLeaderLocalPlayer; /// The entity's current attack or revenge target, or null. public EntityAlive AttackOrRevengeTarget; /// /// Pre-computed search bounds centred on the entity with a radius of /// . Used by V4 utility methods /// that need a bounds for entity queries so the allocation happens once per tick. /// public Bounds SearchBounds; /// /// Shared, pooled buffer for entity-search results. V4 utility methods clear this /// list before use rather than allocating a new one each call, eliminating per-call /// GC pressure from GetEntitiesInBounds queries. /// /// Not thread-safe. All AI updates in 7 Days to Die run on the main thread, /// so sharing a single static instance is safe. Callers must call /// EntityBuffer.Clear() before passing it to any world query. /// /// public static readonly List EntityBuffer = new List(AIConstants.EntityBufferInitialCapacity); /// /// Fills every field of the cache for the current tick. /// Call this once at the start of OnUpdateLive before updating any component. /// public void Populate(EntityAliveSDXV4 entity) { Leader = EntityUtilities.GetLeaderOrOwner(entity.entityId) as EntityAlive; HasLeader = Leader != null; LeaderAsPlayer = Leader as EntityPlayer; // Compute squared distance first (no sqrt); derive DistanceToLeader only if needed. DistanceSqToLeader = HasLeader ? (entity.position - Leader.position).sqrMagnitude : 0f; DistanceToLeader = HasLeader ? UnityEngine.Mathf.Sqrt(DistanceSqToLeader) : 0f; IsLeaderLocalPlayer = HasLeader && GameManager.Instance.World.IsLocalPlayer(Leader.entityId); AttackOrRevengeTarget = EntityUtilities.GetAttackOrRevengeTarget(entity.entityId) as EntityAlive; var r = AIConstants.DefaultNearbySearchRadius; SearchBounds = new Bounds(entity.position, new Vector3(r, r, r)); } }