using Unity.Burst; using Unity.Entities; using Unity.Mathematics; using Unity.NetCode; using Unity.Transforms; namespace ProjectM.Simulation { /// /// Predicted projectile integrator: advances every live along its /// replicated planar (XZ) at its baked , /// accumulating . Runs inside the prediction loop on the /// owning client (re-simulated on rollback) and once per tick on the server, after /// has spawned this tick's shots; filtered to /// so only predicted ghosts move. Deterministic by construction: uses SystemAPI.Time.DeltaTime /// (the fixed tick step) only — no wall-clock, no System.Random. Pure motion: range expiry and /// destruction are server-authoritative in ProjectileDamageSystem, so this system never /// performs structural changes and is fully idempotent across rollback re-simulation. /// [UpdateInGroup(typeof(PredictedSimulationSystemGroup))] [UpdateAfter(typeof(AbilityFireSystem))] [BurstCompile] public partial struct ProjectileMoveSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; foreach (var (transform, projectile) in SystemAPI.Query, RefRW>() .WithAll()) { float step = projectile.ValueRO.Speed * dt; projectile.ValueRW.LastStep = step; float3 dir = new float3(projectile.ValueRO.Direction.x, 0f, projectile.ValueRO.Direction.y); transform.ValueRW.Position += dir * step; projectile.ValueRW.DistanceTravelled += step; } } } }