Game.LocalEffectSystem
Assembly:
Namespace: Game.Buildings
Type: class
Base: GameSystemBase
Summary:
LocalEffectSystem maintains and updates local, spatial modifiers provided by buildings and upgrades (e.g. buff/debuff radii and value modifiers). It stores provider entries in a NativeQuadTree (EffectItem -> EffectBounds) and updates that tree in a worker job (UpdateLocalEffectsJob) as building entities are created/updated/destroyed. It exposes read-only access via ReadData so other systems can query and apply local modifiers efficiently, and provides APIs to coordinate job dependencies for readers and writers. Nested types represent items, bounds and the read-side iterator logic.
Fields
-
private EntityQuery m_UpdatedProvidersQuery
Query selecting LocalEffectProvider entities that were updated or deleted (excluding Temp). Used to update only changed providers. -
private EntityQuery m_AllProvidersQuery
Query selecting all LocalEffectProvider entities (excluding Temp). Used when the whole set needs rebuilding (e.g. on load). -
private NativeQuadTree<EffectItem, EffectBounds> m_SearchTree
Spatial index (quad-tree) storing effect providers keyed by EffectItem with geometry/metadata in EffectBounds. Persistent allocator, updated by UpdateLocalEffectsJob and read via GetReadData(). -
private JobHandle m_ReadDependencies
Combined job handle representing outstanding reader jobs that depend on the tree. -
private JobHandle m_WriteDependencies
Combined job handle representing outstanding writer jobs that update the tree. -
private bool m_Loaded
Flag set when the game serialization signals load; causes a full rebuild on next update. -
private TypeHandle __TypeHandle
Compiler-generated aggregated type handles used to access ECS component types inside jobs.
{{ The system centralises local (per-building) modifier data in a spatial tree and coordinates concurrent reads/writes with JobHandle dependency tracking. }}
Properties
- This type defines no public properties.
{{ Access to runtime data is provided through methods (GetReadData / GetSearchTree) rather than public properties to ensure correct JobHandle synchronization. }}
Constructors
public LocalEffectSystem()
{{ Default constructor; the system relies on OnCreate to initialize queries and the NativeQuadTree. }}
Methods
-
protected override void OnCreate()
Initializes entity queries (m_UpdatedProvidersQuery, m_AllProvidersQuery) and constructs the persistent NativeQuadTree (m_SearchTree). Called when the system is created. -
protected override void OnDestroy()
Disposes the NativeQuadTree and calls base.OnDestroy. Ensures persistent native memory is released on system destruction. -
protected override void OnGameLoaded(Context serializationContext)
Marks the system as loaded (m_Loaded = true) so the next update performs a full rebuild of provider entries. -
private bool GetLoaded()
Internal helper that checks m_Loaded, clears it and returns true if the system was previously marked as loaded. Used to decide whether to use the full provider query. -
protected override void OnUpdate()
Main update loop: chooses either the updated-only query or the all-providers query (if loaded), builds an ArchetypeChunk list asynchronously, schedules UpdateLocalEffectsJob to add/update/remove entries in m_SearchTree, disposes the chunk list after job, then registers the writer dependency with AddLocalEffectWriter. Also composes JobHandle dependencies to respect other system dependencies. -
public ReadData GetReadData(out JobHandle dependencies)
Returns a ReadData struct tied to the current m_SearchTree for read-side queries. Outputs JobHandle dependencies that callers must respect (dependencies = m_WriteDependencies). -
public NativeQuadTree<EffectItem, EffectBounds> GetSearchTree(bool readOnly, out JobHandle dependencies)
Returns the internal NativeQuadTree. If readOnly is true dependencies = m_WriteDependencies; otherwise dependencies is the combined read/write dependencies (JobHandle.CombineDependencies(m_ReadDependencies, m_WriteDependencies)). Use with care: exposing the tree for writing is possible but callers must manage synchronization using the returned dependencies. -
public void AddLocalEffectReader(JobHandle jobHandle)
Register a reader job handle. The system will combine it into m_ReadDependencies so writers will wait for readers. -
public void AddLocalEffectWriter(JobHandle jobHandle)
Register a writer job handle. The system will combine it into m_WriteDependencies so readers/writers are ordered correctly. -
public static void InitializeTempList(NativeList<LocalModifierData> tempModifierList, DynamicBuffer<LocalModifierData> localModifiers)
Copies a prefab's LocalModifierData buffer into a temporary NativeList for processing in jobs. Useful when building the combined modifier list from base prefab modifiers. -
public static void AddToTempList(NativeList<LocalModifierData> tempModifierList, DynamicBuffer<LocalModifierData> localModifiers, bool disabled)
Merges modifiers from an upgrade (or other source) into tempModifierList. If disabled is true, the modifier's delta/radius are zeroed. Identical modifier types are combined according to their RadiusCombineMode; if the same type is present with conflicting modes an Exception is thrown. -
public static bool GetEffectBounds(Transform transform, LocalModifierData localModifier, out EffectBounds effectBounds)
Computes EffectBounds for a provider without efficiency scaling (used for signature/other providers). Returns true if the radius >= 1 and the resulting delta is non-zero (effectively indicates whether this modifier should be added to the tree). -
public static bool GetEffectBounds(Transform transform, float efficiency, LocalModifierData localModifier, out EffectBounds effectBounds)
Computes EffectBounds for a provider using efficiency to interpolate radius and delta. Efficiency influences radius and delta (square-root/neural scaling) before constructing the EffectBounds. Returns whether the computed modifier should be stored (radius >= 1 and delta != 0). -
protected override void OnCreateForCompiler()
Compiler/IL-generated helper that assigns internal query/type handles. Calls __AssignQueries and assigns __TypeHandle handles. Not intended for direct use by modders. -
private void __AssignQueries(ref SystemState state)
IL-generated stub used by OnCreateForCompiler; no runtime query building beyond generated code. -
protected override void OnDestroy()
(Already listed above) Disposes m_SearchTree and performs base cleanup.
Nested types (brief):
-
EffectItem (struct): pairs an entity provider with a LocalModifierType. Implements IEquatable for use as a key in the quad-tree.
-
EffectBounds (struct): contains Bounds2 m_Bounds, uint m_TypeMask (bitmask of modifier types), and float2 m_Delta (x = additive delta, y = multiplicative/relative delta). Implements IBounds2 and merging/intersection logic.
-
ReadData (struct): read-side wrapper holding a NativeQuadTree reference. Exposes ApplyModifier(ref float value, float3 position, LocalModifierType type) which iterates the quad-tree at a point and accumulates additive/multiplicative deltas into the provided value.
-
UpdateLocalEffectsJob (BurstCompile, struct) : IJob
Job that iterates archetype chunks of providers; for created/loaded chunks it adds entries, for updated chunks it updates or removes entries, and for deleted/destroyed chunks it removes entries from the quad-tree. The job builds a temp NativeListper-chunk to merge prefab/base modifiers and installed upgrades then computes effect bounds and updates the m_SearchTree accordingly.
{{ The update job is the place to study if you want to modify how modifiers are combined, which components are considered, or when providers are considered active (Created/Deleted/Destroyed/Signature/Efficiency/etc.). }}
Usage Example
// Example: reading and applying local modifiers safely from another system
// (assumes 'localEffectSystem' is an instance accessible from your system)
JobHandle deps;
var readData = localEffectSystem.GetReadData(out deps);
// If you schedule jobs that will use readData, pass 'deps' as a dependency and then
// call localEffectSystem.AddLocalEffectReader(yourJobHandle) so the system knows about your reader.
// For simple immediate usage on the main thread:
float value = 10f;
float3 position = new float3(123f, 0f, 456f);
readData.ApplyModifier(ref value, position, LocalModifierType.Happiness);
// 'value' is now modified by any applicable local modifiers at that position.
// Example: registering a job that reads the tree
JobHandle myReaderJob = /* schedule your job using 'deps' as input dependency */;
localEffectSystem.AddLocalEffectReader(myReaderJob);
// Example: when you schedule writers (jobs that add/update the tree), call:
localEffectSystem.AddLocalEffectWriter(myWriterJob);
{{ Tips: - Use GetSearchTree(readOnly:true, out JobHandle deps) to obtain the tree reference for read-only operations and to get required synchronization handle. - Call AddLocalEffectReader/AddLocalEffectWriter with the JobHandle from your scheduled job so the LocalEffectSystem can combine dependencies and avoid race conditions. - If you need to emulate how buildings' effective radius scales with efficiency, inspect GetEffectBounds(transform, efficiency, localModifier, out effectBounds) for the exact interpolation logic. }}