public sealed class SyncStateSweepSystemMarks every behaviour whose state or lists changed this frame, once, at the end of it.
As a system
- Phase
- LateUpdate
- Reads
- BehaviorRef NetworkId
- Writes
- SyncListVersion SyncStateVersion
- Runs after
- BehaviorLateUpdateSystem
Remarks
The caller MarkChanged's own remarks already claimed existed. That method says it is "called by the sync system rather than by a setter", and until this system there was no sync system: every caller in the tree was a test, so a game that set a SyncVar`1 and did not remember to call MarkChanged() by hand had its state stay on the server for ever. Nothing failed — SyncStateReplicator`1 simply never saw the entity, because the entity had no SyncStateVersion for the change filter to notice.
A sweep rather than a push, which is the design and not a shortcut. A SyncVar`1 setter cannot mark the entity itself: a behaviour that sets ten of them in one frame would touch the component ten times, and a setter has no way to know it was the last. So the dirt accumulates in managed fields and something walks them once, after everything that writes them has run.
Ordering is the whole of the correctness argument, and it is invisible when it is wrong. A sweep that ran before the behaviours would mark last frame's writes, and the snapshot would ship every change one frame late — which presents as interpolation that feels slightly heavy rather than as a bug. Hence [UpdateAfter(typeof(BehaviorLateUpdateSystem))]: LateUpdate is the last phase in which game logic runs at all, and that system is the last thing in it that can set a SyncVar`1. SyncStateSweepOrderTests asserts the placement off Plan rather than trusting this paragraph.
⚠ The other half of that ordering is the game's, because Capture is the game's. Capture is not a system — a server decides for itself when its tick is — so nothing here can express "before the capture" as an attribute. The rule is that a capture must come after this phase in the same tick: a server that runs EngineLoop.Frame and then captures is already right, and a server that captures inside SystemPhase.FixedUpdate — where NetworkTransformCaptureSystem lives — is one frame behind and should call Sweep itself instead, which is public for exactly that reason and the same reason Publish is.
The dirt is cleared by the capture, not by the sweep, and that is why a sweep is idempotent between captures rather than after one. SyncStateReplicator`1 calls ClearDirty as it writes the record — clearing it here instead would mean a field that changed in a frame the server did not capture is never sent at all. The visible consequence is that a sweep running twice between two captures marks twice: two increments of a counter nothing reads the value of, which is exactly what the counter was chosen to make cheap.
What it costs. The query is BehaviorRef and NetworkId together, so it visits networked entities that carry behaviours and nothing else — a scene of a thousand props costs nothing, and neither does a thousand behaviours on entities the wire has never heard of. Per visited behaviour it is a field-by-field IsDirty with an early exit on the first dirty one, and a HasPending per declared list: O(networked behaviours × fields), with no allocation once the scratch list has grown. It is deliberately not O(dirty) — being O(dirty) is what a push from the setter would buy, and that is the design this type's second paragraph rejects.
Fields and properties (4)
public SystemAccess Accesspublic long MarkedStateCountHow many state marks this has made.
public long MarkedListCountHow many list marks this has made.
public int LastVisitedCountHow many networked behaviours the last sweep looked at.
Methods (3)
public SyncStateSweepSystem(BehaviorStore store)Creates the system.
public override JobHandle Update(in SystemContext context, JobHandle dependency)Runs the system.
public int Sweep(World world)Marks everything whose state or lists changed since the last sweep.
Used by (3)
- GameServerMultiplayer
- SyncStateSweepOrderTestsVixen.Net.Engine.Tests
- SyncStateSweepTestsVixen.Net.Engine.Tests