using System.Collections.Generic; using ProjectM.Simulation; using Unity.Entities; using Unity.Mathematics; using Unity.NetCode; using Unity.Transforms; using UnityEngine; using UnityEngine.UIElements; namespace ProjectM.Client { /// /// Client-only ENEMY VISIBILITY markers — makes living enemies (especially the last one) easy to find so a room /// never devolves into hunting an unseen straggler. Observe-only presentation in /// (same shape as / : /// reads replicated state, never mutates the sim, never destroys a ghost). Owns its own runtime UIDocument /// (sortingOrder 48 — just under the HUD's 50) and a POOL of marker glyphs: each living enemy within /// of the local player gets either a clamped EDGE ARROW when off-screen /// (rotated toward it — the "it's over here" cue, reusing OnboardingSystem's WorldToScreen edge math) or a subtle /// overhead PIP when on-screen. The pips fade toward as the on-screen /// enemy count rises (declutter a swarm); off-screen arrows always stay full so a straggler is never missed. The /// boss is excluded (it has its own HUD presence bar); corpses () are excluded. /// [WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)] [UpdateInGroup(typeof(PresentationSystemGroup))] public partial class EnemyMarkerSystem : SystemBase { const int MaxMarkers = 32; // pool cap (a room never fields this many; when few remain, all are marked) const float Margin = 48f; // screen-edge inset for off-screen arrows (panel units) GameObject _go; UIDocument _doc; bool _built; readonly List