using ProjectM.Simulation;
using Unity.Burst;
using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Server
{
///
/// Server-authoritative expiry of TIMED s. Each tick it walks every entity's
/// server-only buffer; for any row whose has
/// elapsed (wrap-safe compare, never raw uint<) it removes
/// the matching StatModifier(s) by SourceId and the timed row. The shortened StatModifier [GhostField] buffer
/// auto-replicates (OwnerSendType.All), so StatRecomputeSystem reverts the effective stat on both worlds with no
/// change. Runs in the plain server (NOT the predicted loop) so it is applied
/// exactly once and never double-removed on rollback; a DynamicBuffer mutation is not a structural change, so it
/// is safe to mutate the iterated entity's own buffers in place.
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
[UpdateInGroup(typeof(SimulationSystemGroup))]
public partial struct TimedModifierExpirySystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
state.RequireForUpdate(state.GetEntityQuery(ComponentType.ReadOnly()));
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var serverTick = SystemAPI.GetSingleton().ServerTick;
if (!serverTick.IsValid)
return;
foreach (var (timed, mods) in
SystemAPI.Query, DynamicBuffer>())
{
for (int i = timed.Length - 1; i >= 0; i--)
{
uint until = timed[i].UntilTick;
if (until == 0)
continue; // inert (no expiry scheduled)
var untilTick = new NetworkTick(until);
if (untilTick.IsValid && untilTick.IsNewerThan(serverTick))
continue; // not yet due
TimedModifierUtil.RemoveBySourceId(mods, timed[i].SourceId);
timed.RemoveAtSwapBack(i);
}
}
}
}
}