using ProjectM.Simulation;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.NetCode;
using Unity.Transforms;
namespace ProjectM.Server
{
///
/// LANTERN "light is territory" relevancy prototype (Build Spec Phase 1 step 8): per connection, marks every
/// ENEMY ghost OUTSIDE that player's lamp radius IRRELEVANT — so monsters in the dark aren't replicated (the
/// gamma test: "nothing to see"). Players + untagged/global ghosts stay relevant for free (SetIsIrrelevant).
///
/// SHARED-SET DISCIPLINE: is the SOLE clearer of the GhostRelevancy
/// set — its OnUpdate runs every tick (requires only GhostRelevancy), setting the mode + clearing +
/// adding its region hides. This system runs [UpdateAfter(RegionRelevancySystem)] and only ADDS light
/// hides (never clears) via TryAdd (defensive against a ghost hidden by BOTH region and light for one
/// connection — a duplicate Add would throw). Gated on so it runs ONLY in the
/// LANTERN gym; the legacy base/expedition game keeps region relevancy alone. Runs in
/// before GhostSendSystem reads the set. Per-player dim/bright (a
/// variable radius) is the tuning follow-up; the prototype uses .
///
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
[UpdateInGroup(typeof(GhostSimulationSystemGroup))]
[UpdateAfter(typeof(RegionRelevancySystem))]
public partial struct LightRelevancySystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
state.RequireForUpdate(); // prototype: light-as-territory runs only in the LANTERN gym
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// Each in-game connection's player position (per-player lamp radius = the dim/bright follow-up; fixed here).
var connPos = new NativeHashMap(8, Allocator.Temp);
foreach (var (owner, lt) in
SystemAPI.Query, RefRO>().WithAll())
connPos[owner.ValueRO.NetworkId] = lt.ValueRO.Position;
if (connPos.IsEmpty) { connPos.Dispose(); return; }
// The set is already mode=SetIsIrrelevant + cleared + region-populated THIS tick by RegionRelevancySystem.
ref var relevancy = ref SystemAPI.GetSingletonRW().ValueRW;
var set = relevancy.GhostRelevancySet;
var conns = connPos.GetKeyValueArrays(Allocator.Temp);
float rSq = LightRelevancyMath.LampRadiusDefault * LightRelevancyMath.LampRadiusDefault;
foreach (var (ghost, lt) in
SystemAPI.Query, RefRO>().WithAll())
{
int ghostId = ghost.ValueRO.ghostId;
if (ghostId == 0) continue; // ghost id not assigned yet this tick
float3 gp = lt.ValueRO.Position;
for (int i = 0; i < conns.Keys.Length; i++)
{
if (LightRelevancyMath.IsHidden(conns.Values[i], gp, rSq))
set.TryAdd(new RelevantGhostForConnection { Connection = conns.Keys[i], Ghost = ghostId }, 1);
}
}
conns.Dispose();
connPos.Dispose();
}
}
}