Skip to content

Game.Tools.ZoneToolSystem

Assembly:
Namespace: Game.Tools

Type: class

Base: ToolBaseSystem

Summary:
{{ ZoneToolSystem implements the zone-editing tool used by Cities: Skylines 2. It provides multiple interaction modes (FloodFill, Marquee, Paint) and manages raycasting, snapping, preview generation (definition entities), and applying/clearing zone data. The system uses several Burst-compiled jobs (SetZoneTypeJob, SnapJob, CreateDefinitionsJob) to operate on ECS chunk data and to create creation definitions for preview/commit. It integrates with audio, terrain sampling, input actions, and the tool output barrier for deferred commands. The system also maintains state for interaction (Default / Zoning / Dezoning) and supports overwrite behavior and snapping options. }}


Fields

  • public const string kToolID = "Zone Tool"
    {{ Constant tool identifier used by the tool framework. }}

  • private ZonePrefab m_Prefab
    {{ Currently selected zone prefab used for painting/zoning. }}

  • private ToolOutputBarrier m_ToolOutputBarrier
    {{ Barrier used to emit creation/definition entities safely (deferred command buffer producer). }}

  • private AudioManager m_AudioManager
    {{ Reference to audio manager for playing UI/tool sounds. }}

  • private TerrainSystem m_TerrainSystem
    {{ Terrain system used for sampling heights when creating definition quads. }}

  • private EntityQuery m_DefinitionGroup
    {{ EntityQuery used to find and destroy existing temporary definition entities (previews). }}

  • private EntityQuery m_TempBlockQuery
    {{ EntityQuery for temporary blocks (Temp + Block + Cell buffer) used by snapping and SetZoneTypeJob. }}

  • private EntityQuery m_SoundQuery
    {{ EntityQuery used to access ToolUX sound settings data. }}

  • private IProxyAction m_ApplyZone
    {{ Input action proxy for the primary apply action (Apply Zone). }}

  • private IProxyAction m_RemoveZone
    {{ Input action proxy for the secondary apply action (Remove Zone). }}

  • private IProxyAction m_DiscardZoning
    {{ Input action proxy used to discard a zoning operation (marquee-specific discard). }}

  • private IProxyAction m_DiscardDezoning
    {{ Input action proxy used to discard a dezoning operation. }}

  • private IProxyAction m_DefaultDiscardApply
    {{ Default discard action used for primary apply in some modes. }}

  • private IProxyAction m_DefaultDiscardRemove
    {{ Default discard action used for secondary apply in some modes. }}

  • private bool m_ApplyBlocked
    {{ Internal flag used to temporarily block apply behavior (used for marquee interactions). }}

  • private ControlPoint m_RaycastPoint
    {{ Last raycast control point returned by raycaster (world/hit info and source entity). }}

  • private ControlPoint m_StartPoint
    {{ Start control point for ongoing Zoning/Dezoning (used for marquee and drag operations). }}

  • private NativeValue<ControlPoint> m_SnapPoint
    {{ NativeValue wrapper holding the snapped control point computed in a job (persisted Allocator.Persistent). }}

  • private State m_State
    {{ Current interaction state (Default, Zoning, Dezoning). }}

  • private TypeHandle __TypeHandle
    {{ Local struct holding component/buffer type handles and component lookup for jobs; assigned in OnCreateForCompiler. }}


Properties

  • public override string toolID { get; }
    {{ Overrides tool identifier; returns "Zone Tool". }}

  • public override int uiModeIndex { get; }
    {{ Returns current mode as an integer for UI (Mode enum -> index). }}

  • public Mode mode { get; set; }
    {{ Current editing mode: FloodFill, Marquee, or Paint. Changing mode affects raycast/snap behaviour and apply semantics. }}

  • public ZonePrefab prefab { get; set; }
    {{ Selected ZonePrefab. Setter marks the tool as needing update when changed. }}

  • public bool overwrite { get; set; }
    {{ Whether zoning operations overwrite existing zones (used when creating defintions). Defaults to true in OnCreate. }}

  • private protected override IEnumerable<IProxyAction> toolActions { get; }
    {{ Enumerator exposing the tool's actions (apply/remove/discard) for the UI. Yields the configured IProxyActions. }}


Constructors

  • public ZoneToolSystem()
    {{ Default constructor; the system is managed by the ECS world and configured in OnCreate. }}

Nested Types

  • public enum Mode { FloodFill, Marquee, Paint }
    {{ Tool operation modes:
  • FloodFill: fills connected cells of the same type,
  • Marquee: rectangular marquee selection,
  • Paint: cell-by-cell painting. }}

  • private enum State { Default, Zoning, Dezoning }
    {{ Interaction state machine; Default = idle/preview, Zoning = applying zones, Dezoning = removing zones. }}

  • private struct SetZoneTypeJob : IJobChunk
    {{ Burst job that iterates Blocks + Cell buffers and sets each Cell.m_Zone to an input ZoneType. Used for clearing temp blocks. Runs in parallel across chunks. }}

  • private struct SnapJob : IJob
    {{ Burst job that computes the snapped ControlPoint (m_SnapPoint) based on current m_RaycastPoint, mode, state, camera right vector and available temporary block data. It supports:

  • checking for selected cells (FloodFill/Paint),
  • snapping to existing geometry or cell-length grid (Marquee),
  • adjusting hit positions and original entities when snapping to block cells. }}

  • private struct CreateDefinitionsJob : IJob
    {{ Burst job that creates a CreationDefinition + Zoning definition entity (via EntityCommandBuffer) to preview the zoning/clear operation. It computes a Quad3 representing the area depending on mode (FloodFill/Paint/Marquee), adjusts heights using TerrainHeightData, and sets ZoningFlags including Overwrite, FloodFill, Paint, Marquee as appropriate. }}

  • private struct TypeHandle
    {{ Helper struct that stores ComponentTypeHandle/BufferTypeHandle/ComponentLookup for Block and Cell; __AssignHandles fills handles from SystemState. Used to supply type handles to jobs. }}


Methods

  • [Preserve] protected override void OnCreate()
    {{ Initializes subsystem references (ToolOutputBarrier, AudioManager, TerrainSystem), builds entity queries (definition/temp/sound), binds input actions from InputManager, allocates m_SnapPoint (Allocator.Persistent), and sets default overwrite = true. Must call base.OnCreate(). }}

  • [Preserve] protected override void OnDestroy()
    {{ Disposes m_SnapPoint and calls base.OnDestroy(). }}

  • [Preserve] protected override void OnStartRunning()
    {{ Called when system starts running: marks required datasets (zones, areas), resets raycast/start points and state, clears apply block flag. }}

  • private protected override void UpdateActions()
    {{ Updates the enabled/override state of apply/secondary/cancel actions based on current tool state (Default/Zoning/Dezoning) and mode. Uses ProxyAction.DeferStateUpdating() to batch updates. }}

  • protected bool GetAllowApplyZone()
    {{ Returns whether primary apply is allowed given current mode, raycast result, selected block and prefab zone type. For Marquee mode it requires a valid raycast and a matching ZoneData prefab; for FloodFill/Paint it generally allows. Checks buffer contents to determine if any cell differs from the target zone. }}

  • protected bool GetAllowRemoveZone()
    {{ Returns whether secondary apply (remove) is allowed. For Marquee it requires raycast + block; otherwise checks the Cell buffer and returns true if at least one cell has a non-zero zone index. }}

  • public override PrefabBase GetPrefab()
    {{ Returns the current prefab (ZonePrefab) as PrefabBase. }}

  • public override bool TrySetPrefab(PrefabBase prefab)
    {{ Attempts to set the prefab if it is a ZonePrefab. Returns true if successful. }}

  • public override void InitializeRaycast()
    {{ Configures the tool raycast typeMask depending on current mode and whether the selected snap allows existing geometry. FloodFill/Paint use Terrain|Zones; Marquee may use Terrain only or Terrain|Zones depending on snap. If no prefab selected, sets TypeMask.None. }}

  • [Preserve] protected override JobHandle OnUpdate(JobHandle inputDeps)
    {{ Main driver each frame. Handles state transitions and input:

  • Updates actions and early-outs on focus changes.
  • Processes apply/cancel/secondary apply button presses depending on current State and Mode.
  • Manages m_ApplyBlocked for marquee interactions.
  • Delegates to Apply, Cancel, Update or Clear paths which schedule jobs (SnapPoint, SetZoneType, UpdateDefinitions). Returns combined JobHandle of scheduled jobs. }}

  • public override void GetAvailableSnapMask(out Snap onMask, out Snap offMask)
    {{ Defines allowed snap bits per mode:

  • FloodFill/Paint: ExistingGeometry on, CellLength off,
  • Marquee: ExistingGeometry|CellLength available,
  • Always adds ContourLines to both on/off masks. Used by the tool framework to build the effective snapping behavior. }}

  • private JobHandle Clear(JobHandle inputDeps)
    {{ Sets applyMode = ApplyMode.Clear and returns inputDeps (no additional jobs). }}

  • private JobHandle Cancel(JobHandle inputDeps, bool singleFrameOnly = false)
    {{ Handles Cancel logic across states:

  • If Default: plays appropriate remove-start UI sound, potentially moves to Dezoning state, sets applyMode, schedules SnapPoint and UpdateDefinitions.
  • If Dezoning: finalizes dezoning (plays end sounds), resets state to Default and schedules SnapPoint + UpdateDefinitions.
  • Otherwise: resets to Default and updates definitions. Returns resulting JobHandle combining work. }}

  • private JobHandle Apply(JobHandle inputDeps, bool singleFrameOnly = false)
    {{ Handles Apply logic across states symmetrical to Cancel:

  • If Default: plays start sounds, moves to Zoning (unless single-frame), schedules SnapPoint + UpdateDefinitions.
  • If Zoning: finalizes zoning (play end sounds), resets to Default and schedules SnapPoint + UpdateDefinitions.
  • Otherwise: resets state and updates definitions. Returns resulting JobHandle combining work. }}

  • private JobHandle Update(JobHandle inputDeps)
    {{ Called each update when no apply/cancel input triggered. Performs:

  • Raycast result check: if returns control point, may schedule SnapPoint job and then UpdateDefinitions depending on mode/state and whether start point equals snap etc.
  • If no raycast, clears or keeps preview according to current state. Returns JobHandle from SnapPoint / UpdateDefinitions as necessary. Ensures to call JobHandle.ScheduleBatchedJobs() and Complete() at times to read m_SnapPoint synchronously when needed. }}

  • private JobHandle SetZoneType(JobHandle inputDeps)
    {{ If there are temporary blocks, schedules SetZoneTypeJob in parallel to set cells' zone to default(ZoneType) (used to clear temp blocks). Uses type handles from __TypeHandle. }}

  • private JobHandle SnapPoint(JobHandle inputDeps)
    {{ Compute snapped control point using SnapJob. Builds an archetype chunk list for m_TempBlockQuery asynchronously, captures Camera.main.transform.right to pass to job, schedules the SnapJob combining inputDeps with the chunk enumeration job handle, disposes the temp chunk list after scheduled job. If no valid raycast point, clears m_SnapPoint and returns inputDeps. }}

  • private JobHandle UpdateDefinitions(JobHandle inputDeps)
    {{ Destroys existing definition preview entities via DestroyDefinitions(...) and, if there is a valid m_RaycastPoint, schedules CreateDefinitionsJob to create a preview creation definition/Zoning component. Adds the job handle to the tool output barrier producer and to TerrainSystem CPU height reader usage. Returns combined JobHandle. }}

  • [MethodImpl(MethodImplOptions.AggressiveInlining)] private void __AssignQueries(ref SystemState state)
    {{ Compiler helper used in generated code path; here it creates and disposes a temporary EntityQueryBuilder. }}

  • protected override void OnCreateForCompiler()
    {{ Compiler helper: calls base.OnCreateForCompiler, assigns queries and component type/buffer handles using __TypeHandle.__AssignHandles. }}


Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    // typical initialization performed by ZoneToolSystem:
    m_ToolOutputBarrier = base.World.GetOrCreateSystemManaged<ToolOutputBarrier>();
    m_AudioManager = base.World.GetOrCreateSystemManaged<AudioManager>();
    m_TerrainSystem = base.World.GetOrCreateSystemManaged<TerrainSystem>();
    m_SnapPoint = new NativeValue<ControlPoint>(Allocator.Persistent);
    overwrite = true;
}

{{ YOUR_INFO }}