#if UNITY_EDITOR
using ProjectM.Simulation;
using Unity.Collections;
using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Server
{
///
/// MC-0 — EDITOR-ONLY server owner of the authoritative singleton. Ensures+seeds it
/// to in OnCreate, then every ships the
/// FULL config to every connection as a (so a PREDICTING client's DashSystem —
/// including an MPPM thin client that has no overlay — converges on the tuned values; full state, not a delta,
/// so a late-joiner converges in one report). The singleton is mutated by DebugCommandReceiveSystem's
/// SetTuning op (same plain server group). Verbatim DevTelemetrySystem shape. Plain server
/// (NOT the predicted loop); non-Burst (managed-simple, editor-only).
/// Stripped from builds; the wire TYPE + are
/// unconditional, so in a release build no system creates the singleton and consumers fall back to Defaults().
///
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
[UpdateInGroup(typeof(SimulationSystemGroup))]
public partial struct TuningBroadcastSystem : ISystem
{
const uint BroadcastPeriodTicks = 15;
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
if (state.GetEntityQuery(ComponentType.ReadWrite()).IsEmpty)
{
var e = state.EntityManager.CreateEntity(typeof(TuningConfig));
state.EntityManager.SetComponentData(e, TuningConfig.Defaults());
}
}
public void OnUpdate(ref SystemState state)
{
var serverTick = SystemAPI.GetSingleton().ServerTick;
if (!serverTick.IsValid)
return;
uint now = serverTick.TickIndexForValidTick;
if (now == 0 || (now % BroadcastPeriodTicks) != 0)
return;
var report = TuningConfig.ToReport(SystemAPI.GetSingleton());
var ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (var (netId, connEnt) in SystemAPI.Query>().WithEntityAccess())
{
var req = ecb.CreateEntity();
ecb.AddComponent(req, report);
ecb.AddComponent(req, new SendRpcCommandRequest { TargetConnection = connEnt });
}
ecb.Playback(state.EntityManager);
ecb.Dispose();
}
}
}
#endif