#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