using ProjectM.Simulation; using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.NetCode; namespace ProjectM.Server { /// /// Server-authoritative per-connection ghost relevancy for the base/expedition region split. Each tick: /// build a connection -> region map from the region-tagged player ghosts, then mark every region-tagged /// ghost IRRELEVANT to each connection whose player is in a DIFFERENT region. Uses /// so untagged/global ghosts (e.g. the cycle director) /// stay relevant to everyone for free — only cross-region ghosts are hidden. Runs in the /// (before GhostSendSystem reads the set). The set holds /// (connection, ghost) pairs for the CURRENT simulated tick only, so it is cleared and repopulated every /// update. A connection with no spawned player yet is absent from the map and simply sees everything. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] [UpdateInGroup(typeof(GhostSimulationSystemGroup))] public partial struct RegionRelevancySystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate(); } [BurstCompile] public void OnUpdate(ref SystemState state) { // Map each in-game connection (by NetworkId) to its player's region. var connRegion = new NativeHashMap(8, Allocator.Temp); foreach (var (owner, region) in SystemAPI.Query, RefRO>().WithAll()) { connRegion[owner.ValueRO.NetworkId] = region.ValueRO.Region; } ref var relevancy = ref SystemAPI.GetSingletonRW().ValueRW; relevancy.GhostRelevancyMode = GhostRelevancyMode.SetIsIrrelevant; var set = relevancy.GhostRelevancySet; set.Clear(); if (!connRegion.IsEmpty) { var conns = connRegion.GetKeyValueArrays(Allocator.Temp); foreach (var (ghost, region) in SystemAPI.Query, RefRO>()) { int ghostId = ghost.ValueRO.ghostId; if (ghostId == 0) continue; // ghost id not assigned yet this tick byte ghostRegion = region.ValueRO.Region; for (int i = 0; i < conns.Keys.Length; i++) { if (conns.Values[i] != ghostRegion) set.Add(new RelevantGhostForConnection { Connection = conns.Keys[i], Ghost = ghostId }, 1); } } conns.Dispose(); } connRegion.Dispose(); } } }