Skip to content

t1k:unity:dots-core:ecs

FieldValue
Moduledots-core
Version2.3.2
Effortmedium
Tools

Keywords: archetype, auto-destroy, component, cooldown, cooldown timer, CooldownTickHelper, CooldownTimer, csv, DeadTagLifetimeSystem, despawn, DeterministicRandom, dirty, dirty flag, DirtyTag, DOTS, ECS, editor utilities, entity component system, event cleanup, EventCleanupHelper, flat index, grid math, GridMath, ICooldownState, IEnableableComponent signal, lifetime, Lifetime, LifetimeSystem, one-frame event, respawn, respawn reset, RespawnResetHelper, seed guard, SelectNearestTargetSystem, shared primitives, stat ratio, StatMath, system, target selection, TargetEntity, targeting, TargetSelection, TargetSelectionMode, TargetSelector, team, team affiliation, TeamId, timer, unit prefab, weighted sampling, WeightedSampler

/t1k:unity:dots-core:ecs

Contribute back on bug-fix: when this session resolved a non-obvious DOTS gotcha (silent IJobEntity skip, query dedupe, structural-change invalidation, baking order, etc.) that future sessions would benefit from, emit a marker BEFORE your final summary so the lesson reaches the kit: [t1k:lesson kit="theonekit-unity" skill="dots-core:ecs" fragment="references/<file>.md" reason="<one-line>"] The lesson-collector.cjs Stop hook captures it; a background /t1k:sync-back sub-agent files the PR on origin. See rules/telemetry.md for the full pipeline. (The auto-lesson-from-skill-edit.cjs PostToolUse hook in theonekit-core v1.16+ does this automatically when the same session edits a gotchas reference file — but emitting the marker yourself is still the canonical path when the fix lives in code only.)

  • DOTS — Data-Oriented Technology Stack
  • ECS — Entity Component System
  • ECB — EntityCommandBuffer

Reference for Unity Entities 1.4.x patterns. Covers the full authoring-to-runtime pipeline: baking GameObjects into entities, defining components, writing Burst-compiled systems, querying entities, and performing structural changes safely.

IAspect is deprecated in Entities 1.4+ (will be removed in a future release) — prefer direct SystemAPI.Query usage.

Related skills: dots-jobs-burst (Jobs, Burst, Collections, Math) · dots-physics (Physics) · dots-graphics (Rendering).


  • Writing IComponentData, ICleanupComponentData, IEnableableComponent, ISharedComponentData, IBufferElementData
  • Implementing ISystem or SystemBase systems
  • Using SystemAPI.Query, SystemAPI.GetComponent, SystemAPI.GetSingleton
  • Creating Baker(T) authoring components or baking systems
  • Using EntityCommandBuffer, EntityManager, EntityQuery
  • Writing IJobEntity jobs with ECS
  • Setting up LocalTransform, parent/child hierarchies
  • Configuring system ordering, update groups, custom worlds

TaskReference File
IComponentData, tags, ICleanupComponentData, IEnableableComponentcomponents-guide.md
ISharedComponentData, Chunk Components, DynamicBufferbuffers-shared-guide.md
ISystem, SystemBase, SystemAPI.Querysystems-guide.md
EntityQuery builder, system ordering, update groupsquery-ordering-guide.md
Worlds, bootstrap, custom worlds, IAspect (deprecated)worlds-aspect-guide.md
EntityManager, EntityCommandBuffer, structural changes, ECB parallel writerentities-ecb-guide.md
Baker, authoring MonoBehaviour, subscenes, baking systems, blob assets in bakerbaking-guide.md
LocalTransform, parent/child hierarchy, TransformUsageFlagstransforms-guide.md
IJobEntity scheduling, parallel writer, query filteringjobs-guide.md
Advanced system patterns, system state, singleton patternssystems-advanced-guide.md
IEnableableComponent pattern, LINQ policy, performance prioritypatterns-guide.md
Editor utils: UnitArchetypeConfig, UnitAttackType, UnitPrefabUtility, CsvReadereditor-utilities-guide.md
EventCleanupHelper — generic ClearBuffer / DisableEnableable for one-frame eventsevent-cleanup-helper-guide.md
CooldownTimer / CooldownTimerSystem / ICooldownState — countdown timer patterncooldown-timer-guide.md
Lifetime / LifetimeSystem / DeadTagLifetimeSystem — auto-destroy countdown + dead-entity bridgelifetime-guide.md
TargetEntity / TargetSelector / SelectNearestTargetSystem — generic target selectiontargeting-guide.md
RespawnResetHelper — standard respawn-ready query builderrespawn-reset-helper-guide.md
DirtyTag — generic enableable dirty/recalculate signal (replaces StatsDirtyTag etc.)dirty-tag-guide.md
TeamId — canonical team affiliation component (SSOT)team-id-guide.md
Shared Burst primitives — GridMath, StatMath.Ratio, WeightedSampler, CooldownTickHelper, DeterministicRandom (dots-core SSOT)shared-burst-primitives.md

Anti-Patterns for Cross-Project Reusability

Section titled “Anti-Patterns for Cross-Project Reusability”
Anti-PatternSymptomFix
God component10+ fields, multiple concernsSplit: Config + State + Stacking (e.g., a large stats component → 3 focused components)
Factory switch systemswitch(enumType) with 3+ casesTag dispatch: separate systems per tag
God orchestrator moduleAsmdef references ALL other modulesPer-module cleanup triggered by shared signal tag
Embedded componentComponent defined inside system fileOne type per file, in Components/ folder
Cross-module enumEnum in Module A, used by Module B+CMove to shared Core module (e.g., DamageType, CCType)
Mixed constantsVisual + combat + physics in one classSplit per domain: CombatConstants, VisualConstants, PhysicsLayerConfig
Boolean config stateRespawn.Enabled booleanUse IEnableableComponent (RespawnConfig now toggleable)
Monolithic respawnSingle system resets all statePer-module resets + RespawnReadyTag bridge (atomic module cleanup)
Visual transform feedback loopPresentationSystemGroup modifies Position each frame → simulation reads modified value next frame → positions collapse exponentiallySave/restore pattern: store canonical value in dedicated component (e.g., SideViewGameZ) → restore at SimulationSystemGroup OrderFirst → simulate on canonical data → remap in PresentationSystemGroup

See: dots-architecture/references/atomicity-guide.md for full audit checklist.

→ See references/patterns-guide.md for IEnableableComponent pattern, LINQ policy, and performance priority rules.

Namespace layout convention:

  • [YourProject] — root
  • [YourProject].Components — IComponentData structs
  • [YourProject].Systems — ISystem structs
  • [YourProject].Authoring — MonoBehaviour + Baker(T)
  • [YourProject].Jobs — IJobEntity structs
  • [YourProject].Physics — physics components and systems
  • [YourProject].Rendering — rendering components and material overrides

Package versions:

  • com.unity.entities 1.4.5
  • com.unity.burst 1.8.28
  • com.unity.collections 2.6.5
  • com.unity.mathematics 1.3.2
  • com.unity.entities.graphics 1.4.18

Critical rules:

  • To use Burst on an ISystem, mark both the struct and each method [BurstCompile], and make the struct partial
  • To defer structural changes inside a job, use EntityCommandBuffer.ParallelWriter with [ChunkIndexInQuery] sort key
  • To enable/disable a component without archetype moves, implement both IComponentData and IEnableableComponent
  • NEVER use GetSingletonEntity<T>(), HasSingleton<T>(), or TryGetSingletonEntity<T>() on IEnableableComponent types — throws InvalidOperationException. Use SystemAPI.Query<RefRW<T>>().WithPresent<T>().WithEntityAccess() instead
  • To bake a moving entity, pass TransformUsageFlags.Dynamic to GetEntity() in the Baker
  • To build large read-only shared data, use BlobAsset and register via baker.AddBlobAsset()
  • To detect entity destruction, use ICleanupComponentData — it survives DestroyEntity until explicitly removed

→ See references/gotchas-structural.md for stale cache after type changes, SetComponentEnabled structural change gotcha, two-pass pattern, and the default (uninitialized) EntityQuery NRE (guard .IsEmpty/.CalculateEntityCount() with query.IsCreated).

Three patterns for one-frame inter-system events:

  • IEnableableComponent (*Event/*DirtyTag) — stateless signals, no payload. Cleanup system disables via IJobEntity at OrderFirst.
  • DynamicBuffer per-entity (*Event : IBufferElementData) — payloaded events scoped to one entity. Consumer or cleanup system calls buffer.Clear().
  • DynamicBuffer singleton (EntityEvent) — global cross-system queue with EntityEventType discriminator. Cleared by CoreEventCleanupSystem.

Cross-assembly gotcha: IJobEntity in a cleanup system MUST live in the same assembly as the event component type. Cross-assembly job definitions cause Burst source generation job safety errors.

→ Full patterns, checklist, and cleanup system map: dots-rpg/references/event-conventions.md

Since unity-dots-library v2.0.0 (2026-05-23) all prefab fields in library bakers + demo authoring use AssetReferenceGameObject, not raw GameObject. The bake helper is AssetReferenceBakerExtensions.BakeAssetReference(...) (SSOT in com.the1studio.dots-core).

  • Runtime-asmdef bans (enforced by AddressablesEnforcementTests): no Resources.Load(, no AssetDatabase.LoadAssetAtPath, no Object.Instantiate(GameObject) outside the per-project allowlist. ECS-side EntityManager.Instantiate(Entity) and ecb.Instantiate(Entity) are fine — different overload, different target.
  • In a Baker, never call GetEntity(prefab) directly on an AssetReferenceGameObject. Use the helper — it handles the weak-reference indirection and produces a baked Entity reference for runtime spawning.

→ See dots-architecture/references/addressables-pattern.md for the full authoring → baker → runtime flow.

Every ISystem must satisfy all of the following before merge:

  1. [BurstCompile] on struct AND on OnUpdate/OnCreate/OnDestroy — exception: OnCreate with structural changes.
  2. [RequireMatchingQueriesForUpdate] on any system whose query may be empty at startup or in idle frames — BUT ONLY if the system registers at least one query (inline SystemAPI.Query, IJobEntity scheduling, or OnCreate RequireForUpdate<T>). NEVER put RMQFU on a system whose OnUpdate only delegates to a static helper that builds its query internally (e.g. EventCleanupHelper.ClearBuffer<T>) — RMQFU sees zero registered queries and deadlocks: OnUpdate never runs. Drop RMQFU and run unconditionally instead (the helper’s WithAll<T> makes the empty case a cheap no-op). Catastrophic, silent, no error. Caught in library 412f905 (13 dead cleanup systems). → full explanation: references/event-cleanup-helper-guide.md § “CATASTROPHIC GOTCHA”.
  3. No EntityManager.AddComponent/RemoveComponent/AddBuffer/DestroyEntity in OnUpdate loops — use ECB.
  4. ComponentLookup<T> and BufferLookup<T> cached in OnCreate, updated via .Update(ref state) each OnUpdate — never created per-frame.
  5. ScheduleParallel jobs use [ChunkIndexInQuery] as ECB sort key — never raw entity index.

→ Full 38-pattern checklist with W4 baseline stats + T1/T7/T8/T11 guidance: references/best-practices.md → IEnableableComponent vs. DisabledTag decision guide: references/ienableable-vs-disabledtag.md → ComponentLookup/BufferLookup caching patterns: references/component-lookup-caching.md → ECB system selection, parallel writer, sort key gotchas: references/ecb-patterns.md → BlobAssetReference construction, baker registration, runtime lifetime: references/blob-assets.md → ISharedComponentData partitioning, uniqueness ceiling, chunk fragmentation: references/shared-components.md → SystemState vs. SystemAPI access pattern decision guide: references/system-state-vs-systemapi.md → Burst + source-gen gotchas — BC1028, OnCreate no-op, missing [BurstCompile] clusters, SGFE011 (open-generic DynamicBuffer in SystemAPI.Query): references/gotchas-burst.md