Game.Areas.SurfaceExpandSystem
Assembly:
Game (inferred from namespace and typical project layout)
Namespace:
Game.Areas
Type:
Class (derived from GameSystemBase)
Base:
GameSystemBase
Summary:
SurfaceExpandSystem is an ECS system responsible for computing per-node expansion offsets (Expand buffers) for surface areas (Surface components). It inspects the owning building's prefab and transform, nearby road/net connections and subobjects, and building flags (e.g., Left/Right/Back access) to determine where the area should expand relative to each perimeter node. The main work is performed in a Burst-compiled IJobChunk (ExpandAreasJob) scheduled in OnUpdate, which updates the Expand dynamic buffers for each Surface entity.
Fields
-
private EntityQuery m_UpdatedAreasQuery
Query matching Surface entities whose Expand buffer has been updated (includes Surface, Expand, Updated; excludes Temp and Deleted). Used when only incremental updates are needed. -
private EntityQuery m_AllAreasQuery
Query matching all Surface entities with Expand buffers (excludes Temp and Deleted). Used after a full load to recompute everything at once. -
private bool m_Loaded
A flag set by OnGameLoaded to request a full recomputation on the next update. GetLoaded() will consume and reset this flag. -
private TypeHandle __TypeHandle
Internal structure holding ComponentTypeHandle/BufferTypeHandle/ComponentLookup/BufferLookup instances used to populate the ExpandAreasJob. Assigned in OnCreateForCompiler and used each update to obtain type handles for multi-threaded job scheduling.
Properties
- None (this system does not expose public properties)
Constructors
public SurfaceExpandSystem()
Default constructor. The class is annotated with [Preserve] on lifecycle methods but the constructor itself is just the default and does not perform additional initialization beyond base.
Methods
-
[Preserve] protected override void OnCreate()
Initializes entity queries used by the system: m_UpdatedAreasQuery (incremental) and m_AllAreasQuery (full). Called once when the system is created. -
[Preserve] protected override void OnGameLoaded(Context serializationContext)
Called when the game finishes loading; sets m_Loaded = true so that the next OnUpdate will recompute all areas using m_AllAreasQuery. -
private bool GetLoaded()
Helper that returns true once when m_Loaded is set and resets m_Loaded to false. Used to decide in OnUpdate whether to schedule a full pass. -
[Preserve] protected override void OnUpdate()
Main update loop. Chooses between m_AllAreasQuery (if a full recompute was requested via GetLoaded()) or m_UpdatedAreasQuery (incremental). If the chosen query is not empty, it builds and schedules the Burst-compiled ExpandAreasJob (IJobChunk) in parallel using JobChunkExtensions.ScheduleParallel, passing in component/buffer handles and lookups from __TypeHandle via InternalCompilerInterface and updates base.Dependency. -
protected override void OnCreateForCompiler()
Internal helper called by the compiler to assign queries and to initialize __TypeHandle handles via __AssignQueries and __TypeHandle.__AssignHandles. Ensures the system has its type handles ready for scheduling jobs. -
[MethodImpl(MethodImplOptions.AggressiveInlining)] private void __AssignQueries(ref SystemState state)
Generated helper used in OnCreateForCompiler. (Here it just creates and disposes an EntityQueryBuilder in the decompiled output; in real compiled code it sets up query metadata for the compiler.)
Nested type: ExpandAreasJob (private struct, [BurstCompile], implements IJobChunk)
- Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
For each chunk, gets Owner component array, Node buffer accessor and Expand buffer accessor. For each entity in the chunk it:
- Resolves the top-level owner building entity (follows Owner links until a Building is reached).
- If a PrefabRef and Transform and corresponding BuildingData exist, calls Calculate(...) to compute per-node Expand offsets; otherwise calls Clear(...) to zero the Expand buffer.
Uses a temporary NativeList
-
Clear(DynamicBuffer
expands)
Resets each Expand element to default (zero) when a valid building/prefab cannot be resolved. -
Calculate(DynamicBuffer
expands, DynamicBuffer nodes, NativeList connections, Entity building, Transform transform, BuildingData prefabBuildingData)
Core algorithm that: - Computes the building footprint quad (using BuildingUtils.CalculateCorners) and orientation offsets (for front/back/left/right offsets).
- For each node around the surface polygon, checks proximity to building borders (CheckBorders) and whether actual connections cross the corresponding edge ranges (CheckConnections).
- When connections are relevant, it ensures connections are filled (FillConnections) which inspects subobjects and subnets to find incoming/outgoing lines.
-
Based on checks, populates Expand entries with offset vectors to expand surface near driveways/road connections while respecting prefab access flags (Left/Right/BackAccess).
-
FillConnections(NativeList
connections, Entity building, Quad2 quad, BuildingData prefabBuildingData)
Clears and then populates connections by calling AddConnections on subobjects / subnets of the building. -
AddConnections overloads:
- AddConnections(NativeList
connections, Entity owner, Quad2 quad, BuildingData prefabBuildingData)
Traverses subobjects (and recursively subobject extensions) and subnets attached to the owner building, delegating to other overloads. - AddConnections(NativeList
connections, Game.Objects.SubObject subObject, Quad2 quad, BuildingData prefabBuildingData)
Checks if a subobject is an extension and recurses; inspects AccessLane + RouteLane components and their curves to build a Line2.Segment representing the connection and adds it if it intersects relevant prefab sides. -
AddConnections(NativeList
connections, Game.Net.SubNet subNet, Quad2 quad, BuildingData prefabBuildingData)
For a SubNet, iterates connected edges (via ConnectedEdge buffer), filters edges by ownership and marker flags, and looks at connected nodes to build Line2.Segment entries for the connection to the building. -
CheckConnectionOwner(Entity owner) : bool
Returns true when the referenced prefab geometry indicates the edge is not a "Marker" (i.e., an actual road/net connection). Uses PrefabRef and NetGeometryData to inspect flags. -
AddConnection(NativeList
connections, Line2.Segment line, Quad2 quad, BuildingData prefabBuildingData)
Tests intersection of the connection line against each side of the building quad (ab, bc, cd, da). When an intersection occurs it stores the parametric t value at the corresponding float4 component (mapping to edges/back/right/front/left as applicable). Only adds entries where at least one relevant intersection exists. The float4 values are initialized to -1 and set to the t param when an intersection is found. -
CheckConnections(float4 border1, float4 border2, NativeList
connections) : bool4
Given the t values for two border-adjacent nodes, computes a min/max range (accounting for -1 as absent) and tests if any connection float4 in the connections list has components that fall within the range. Returns a bool4 indicating which sides have matching connections in that node interval. -
CheckBorders(Quad2 quad, float2 position, BuildingData prefabBuildingData, float borderDistance) : float4
For a single node position, tests the distance to each side of the quad (edges ab, bc, cd, da). If the distance is less than borderDistance and the prefab has the relevant Access flags, returns the param t for that side in a float4 (otherwise -1). Used to determine whether a node is close enough to a building border to be considered for expansion. -
void IJobChunk.Execute(...) (explicit interface implementation)
For compatibility with the IJobChunk interface; simply calls the strongly typed Execute().
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// The system already sets up queries for incremental and full updates:
m_UpdatedAreasQuery = GetEntityQuery(ComponentType.ReadOnly<Surface>(),
ComponentType.ReadOnly<Expand>(),
ComponentType.ReadOnly<Updated>(),
ComponentType.Exclude<Temp>(),
ComponentType.Exclude<Deleted>());
m_AllAreasQuery = GetEntityQuery(ComponentType.ReadOnly<Surface>(),
ComponentType.ReadOnly<Expand>(),
ComponentType.Exclude<Temp>(),
ComponentType.Exclude<Deleted>());
}
Additional notes: - The heavy lifting is done in a Burst-compiled job (ExpandAreasJob) that operates on chunks in parallel for performance. - The system depends on many component lookups and buffer lookups (Owner, Node, Expand, Curve, Edge, Net.Node, Transform, Building, Extension, AccessLane, RouteLane, PrefabRef, BuildingData, NetGeometryData, SubNet, ConnectedEdge, ConnectedNode, SubObject). When creating or modifying custom building prefabs or net geometry in mods, ensure these components/flags are set correctly if you want Surface expansions to reflect connections correctly. - The algorithm uses a small distance threshold derived from AreaUtils.GetMinNodeDistance(AreaType.Surface) * 0.5 to decide if nodes are considered "on the border". This value can be important when debugging why an Expand entry is or isn't being set.