Game.UpdateSystem
Assembly: Assembly-CSharp.dll
Namespace: Game
Type: class
Base: GameSystemBase
Summary:
UpdateSystem manages ordered execution of ComponentSystemBase-derived systems for the game. It groups systems by SystemUpdatePhase, resolves ordering and inter-system dependencies, assigns update intervals and offsets (power-of-two intervals), and drives both CPU and GPU systems. GPU systems implementing IGPUSystem are executed each frame via Unity's RenderPipeline beginFrameRendering callback. The system builds an internal update list and per-phase ranges, and it supports conditional updates using updateIndex/iterationIndex for low-frequency updates and dependency resets on GameSystemBase systems.
Fields
-
private List<IGPUSystem> m_GPUSystems
Holds registered GPU systems (IGPUSystem). These are iterated and executed in OnBeginFrame using CommandBuffer/ScriptableRenderContext. -
private List<SystemData> m_Systems
Temporary list of registered systems (SystemData) used as the input to the refresh/order resolution pass. -
private List<SystemData> m_Updates
Final ordered list of systems to update after Refresh() resolves ordering, offsets and intervals. -
private List<int2> m_UpdateRanges
Per-phase ranges into m_Updates. Each entry stores an int2(startIndex, endIndex) for a SystemUpdatePhase so Update(phase) iterates only that slice. -
private Dictionary<ComponentSystemBase, List<SystemData>> m_RefMap
Mapping from a system to systems that must be ordered relative to it (used for UpdateBefore/After registrations). Used to walk dependencies when building the update order and to inherit offsets. -
private int m_AddIndex
Monotonic counter used to influence ordering when registering systems. Adjusted by UpdateBefore/After helpers (±1,000,000) to bias order. -
private bool m_IsDirty
Flag indicating the internal ordering (m_Updates / m_UpdateRanges) is out-of-date and needs Refresh() before running updates.
Properties
public SystemUpdatePhase currentPhase { get; private set; }
Tracks the SystemUpdatePhase currently being executed by Update(). Set before iterating the range for the phase and restored afterwards. Useful for systems that need to know which phase is running.
Constructors
public UpdateSystem()
Default constructor (marked [Preserve] in source). Initializes the system instance; real initialization of collections happens in OnCreate().
Methods
-
protected virtual void OnCreate()
Initializes internal collections, subscribes to RenderPipelineManager.beginFrameRendering, and sets currentPhase to Invalid. Allocates lists for GPU systems, registered systems, updates and ref map. -
protected virtual void OnBeginFrame(ScriptableRenderContext renderContext, Camera[] cameras)
Called via RenderPipelineManager.beginFrameRendering. Iterates m_GPUSystems and, for each enabled system, creates a CommandBuffer, sets async compute flags if required, calls IGPUSystem.OnSimulateGPU(commandBuffer), executes the command buffer (async or not) on the provided ScriptableRenderContext, then submits and releases the buffer. -
protected override void OnUpdate()
Empty override in source — UpdateSystem does not use the standard OnUpdate loop directly; it exposes Update(...) methods that are invoked by the game loop. -
protected override void OnDestroy()
Unsubscribes from RenderPipelineManager.beginFrameRendering, clears GPU systems list, then calls base.OnDestroy(). -
public void RegisterGPUSystem<SystemType>() where SystemType : ComponentSystemBase, IGPUSystem
Generic helper to get-or-create and register a GPU system from the World. -
public void RegisterGPUSystem(IGPUSystem system)
Registers a concrete IGPUSystem instance into m_GPUSystems if not already present. -
public void UpdateAt<SystemType>(SystemUpdatePhase phase) where SystemType : ComponentSystemBase
Registers a system to update in the given phase with default add-index ordering. Internally calls Register(++m_AddIndex, system, phase). -
public void UpdateBefore<SystemType>(SystemUpdatePhase phase) where SystemType : ComponentSystemBase
Registers a system to be ordered before others by subtracting 1,000,000 from the add-index. Calls Register(++m_AddIndex - 1000000, ...). -
public void UpdateAfter<SystemType>(SystemUpdatePhase phase) where SystemType : ComponentSystemBase
Registers a system to be ordered after others by adding 1,000,000 to the add-index. Calls Register(++m_AddIndex + 1000000, ...). -
public void UpdateBefore<SystemType, OtherType>(SystemUpdatePhase phase) where SystemType : ComponentSystemBase where OtherType : ComponentSystemBase
Registers SystemType to update before OtherType in the given phase. Creates an explicit reference in m_RefMap so Update ordering will place SystemType relative to OtherType. -
public void UpdateAfter<SystemType, OtherType>(SystemUpdatePhase phase) where SystemType : ComponentSystemBase where OtherType : ComponentSystemBase
Registers SystemType to update after OtherType (creates reference opposite to UpdateBefore). -
public void Update(SystemUpdatePhase phase)
Executes all systems registered for the given phase. If m_IsDirty is true, Refresh() is called first. The method looks up the int2 range from m_UpdateRanges for the phase and iterates m_Updates from start to end, calling each system's Update() and catching/logging exceptions via COSystemBase.baseLog.CriticalFormat. currentPhase is set while iterating and restored afterward. -
public void Update(SystemUpdatePhase phase, uint updateIndex, int iterationIndex)
Conditional update that takes an updateIndex bitmask and iterationIndex. For each system in the phase range, it checks (updateIndex & (interval-1)) == offset to decide whether to run that system this tick. If systemData.m_ResetInterval <= iterationIndex and the system is a GameSystemBase, ResetDependency() is invoked before Update(). Exceptions are logged similar to the other Update overload. -
private void Register(int addIndex, ComponentSystemBase system, SystemUpdatePhase phase)
Internal registration helper that computes interval/offset (via GetInterval) and adds a SystemData entry to m_Systems, marking m_IsDirty. -
private void Register(int addIndex, ComponentSystemBase system, ComponentSystemBase other, SystemUpdatePhase phase)
Internal registration helper that records a dependency (system must be ordered relative to other). Adds the entry into m_RefMap[other] and marks m_IsDirty. -
public static void GetInterval(ComponentSystemBase system, SystemUpdatePhase phase, out int interval, out int offset)
Reads interval and offset from a GameSystemBase (if system is GameSystemBase) using GetUpdateInterval/GetUpdateOffset for the phase. Defaults interval=1 and offset=-1. Throws Exception if interval is not a power of two (math.ispow2 check). -
private void Refresh()
Recomputes m_Updates and m_UpdateRanges from m_Systems and m_RefMap. Sorts by phase and add-index, then for each phase builds IntervalData entries, assigns offsets (so systems with the same interval get assigned offsets that distribute them across updateIndex space), and patches inherited offsets based on reference dependencies. This method sets m_IsDirty = false and may throw if dependencies are too deep. -
private void AddSystemUpdate(List<IntervalData> intervalList, SystemData systemData, bool inheritOffset, int safety)
Recursive helper used by Refresh() to add systems (and their referenced systems) into m_Updates and intervalList. Takes care of offset inheritance for referenced systems and prevents infinite recursion via a safety counter (throws if depth >= 100). -
private void PatchSystemOffset(ref int updateIndex, SystemData systemData, bool inheritOffset, int safety)
Recursive helper used after sorting interval entries to propagate offsets into earlier added m_Updates entries (when inheritOffset is true). Also uses a safety counter to detect excessive recursion.
Notes about error handling and constraints: - GetInterval requires intervals be powers of two; otherwise an Exception is thrown. - Recursion depth in AddSystemUpdate and PatchSystemOffset is protected by a safety parameter and throws "Too deep system order" if depth reaches 100. - System.Update() exceptions are caught and logged with phase and system type.
Usage Example
// Example: Registering a GPU system and scheduling systems in phases.
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// Register a GPU system managed by the World
// UpdateSystem is a Game system in the World; obtain it and register a GPU system
var updateSystem = World.GetOrCreateSystemManaged<Game.UpdateSystem>();
updateSystem.RegisterGPUSystem<MyGPUSystem>(); // MyGPUSystem : ComponentSystemBase, IGPUSystem
// Schedule some systems for phases
updateSystem.UpdateAt<MySystem>(SystemUpdatePhase.Simulation);
updateSystem.UpdateAfter<OtherSystem, MySystem>(SystemUpdatePhase.Simulation);
// Later in the game loop, when ticking phases:
updateSystem.Update(SystemUpdatePhase.Simulation, updateIndex: currentTick, iterationIndex: frameIteration);
}
{{
- Implementation notes: UpdateSystem is the central coordinator for deterministic execution ordering of game systems. When adding custom systems in mods, register them via UpdateAt/UpdateBefore/UpdateAfter to ensure correct ordering and to participate in interval-based skipping. Use RegisterGPUSystem for GPU-driven compute/dispatch work that should run every frame.
- Intervals and offsets: Systems inheriting from GameSystemBase should override GetUpdateInterval/GetUpdateOffset for each phase to control how often they run. Intervals must be powers of two.
- Dependency registration: Use the generic UpdateBefore