Skip to content

t1k:unity:dots-core:subscene

FieldValue
Moduledots-core
Version2.3.2
Efforthigh
Tools

Keywords: baking, DOTS, scene management, subscene

/t1k:unity:dots-core:subscene

Handles SubScene authoring → baking → runtime entity loading patterns. Does NOT handle general ECS patterns (→ dots-ecs) or architecture decisions (→ dots-architecture).

Authoring (MonoBehaviour) → Baker → BlobAsset/Entity → EntityScene (.entities file)
  1. Add SubScene component to a GameObject in the Editor scene
  2. Unity bakes GameObjects inside to entities on save / domain reload
  3. At runtime, SceneSystem.LoadSceneAsync loads the .entities binary
class MyBaker : Baker<MyAuthoring>
{
public override void Bake(MyAuthoring authoring)
{
var entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponent(entity, new MyComponent { Value = authoring.value });
// Declare dependency so baker re-runs when referenced asset changes:
DependsOn(authoring.referencedAsset);
}
}

GetEntity flags:

  • TransformUsageFlags.Dynamic — entity has LocalTransform, needs per-frame updates
  • TransformUsageFlags.Renderable — entity renders but doesn’t move
  • TransformUsageFlags.None — pure data entity, no transform overhead

DependsOn(obj) — re-bake when obj changes (prefabs, ScriptableObjects, textures).

ModeWhenTradeoff
LiveConversionEditor Play ModeFast iteration; some fidelity gaps
Full bakeBuild / asset importAccurate; slower

LiveConversion only processes dirty objects — don’t assume full re-bake on every change.

MonoBehaviours that must stay managed (physics callbacks, third-party SDKs):

  • Add a CompanionLink component via baker
  • Unity keeps the GameObject alive and syncs its transform from entity
  • Never add both an ECS component and a managed component for the same data
// Async load
var sceneEntity = SceneSystem.LoadSceneAsync(state.WorldUnmanaged,
new Unity.Entities.Hash128(sceneGUID));
// Check loaded
bool ready = SceneSystem.IsSceneLoaded(state.WorldUnmanaged, sceneEntity);
// Section loading (large worlds)
SceneSystem.LoadSceneAsync(state.WorldUnmanaged, guid,
new SceneSystem.LoadParameters { AutoLoad = false });
// Then manually load sections by index
  • Stale cache: after changing a Baker, delete Library/EntityScenes and reimport to force full rebake
  • Baking order: Bakers run in undefined order — never read another entity’s component inside a Baker; use GetEntity references only
  • Shared components during baking: ISharedComponentData values affect chunk assignment at bake time; changing them post-bake causes chunk moves
  • Transform flattening: deep GameObject hierarchies become flat entity lists — parent-child transform relationships are baked into LocalTransform offsets, not preserved as ECS hierarchy unless TransformUsageFlags.Dynamic is set with WithDynamicUsage
  • BlobAssetReference: must be created via BlobBuilder inside Baker; not valid to create at runtime outside a Baker
  • Library/EntityScenes/ is empty under Unity 6 — bakes live in Library/Artifacts/ (2026-05-23). The legacy advice “delete Library/EntityScenes to force rebake” still works for triggering a re-import, but do NOT use the directory’s emptiness as a signal that “no bake happened”. Unity 6 stores baked entity-scene artifacts in Library/Artifacts/<2-char-prefix>/<full-hash> plus the binary Library/ArtifactDB. The authoritative bake-success signal in Logs/AssetImportWorker*.log is the line -> (artifact id: '<hash>') in N seconds — a missing/zero-byte EntityScenes dir is normal in Unity 6 + Entities 1.4.
  • Stale baker exceptions in worker logs mask the current bake state (2026-05-23). When debugging a SubScene that fails to spawn entities, grepping the worker log for InvalidOperationException or Required prefab matches BOTH today’s failure AND every prior failed bake going back to the log’s creation. Always pivot from grep to a line-number-anchored sed -n 'N,Mp' covering only the latest Start importing Assets/SceneDependencyCache/<guid>... block for the SubScene of interest. The latest block’s contents (presence/absence of exceptions, the closing artifact id: line) is the only signal of current state.
  • Assets/SceneDependencyCache/*.sceneWithBuildSettings must be gitignored (2026-05-23). Every SubScene bake writes one <guid>.sceneWithBuildSettings file (and its .meta) into Assets/SceneDependencyCache/. These are bake-output artifacts that regenerate on every Play-mode entry — they have no source-of-truth value and will appear as untracked spam on every clone. The stock Unity .gitignore template does NOT cover them. Add the following lines to every Unity DOTS project’s .gitignore (alongside the standard “Packed Addressables” entry):
    # SubScene bake artifacts — regenerated on every bake
    /[Aa]ssets/[Ss]ceneDependencyCache/*.sceneWithBuildSettings
    /[Aa]ssets/[Ss]ceneDependencyCache/*.sceneWithBuildSettings.meta
    Test: after enter-then-exit Play mode, git status --short should NOT show any new SceneDependencyCache/ entries. If it does, the gitignore lines above are missing or mis-cased on a non-case-insensitive filesystem.
  • SubScene bake exceptions are invisible in the Play console — check the AssetImportWorker log (2026-05-29). SubScene baking runs in an AssetImportWorker process, NOT the main editor. A baker throwing during bake (e.g. AssetReferenceBakerExtensions.ResolveBakedEntityRequired on an unassigned/empty-GUID AssetReferenceGameObject) aborts the ENTIRE SubScene bake, producing a silent 0-entity or partial-entity result with NO error in the runtime Play console — the exception is written to Logs/AssetImportWorker*.log instead. Diagnosis: when a SubScene bakes too few entities, grep -nE "InvalidOperationException|AssetReferenceBaker|<BakerName>" Logs/AssetImportWorker*.log — the stack trace names the exact baker + authoring (e.g. DOTSCombat.ArrowPrefabBaker.Bake at ArrowPrefabAuthoring.cs:37). One unwired AssetReference on one authoring can zero out an entire demo’s spawn. Real incident: BattleDemoSideView spawned 0 units because an empty-GUID arrow AssetReference aborted the bake; no console error; a debugger stalled twice (149K/178K tokens) chasing it via the Play console before the worker log revealed it. (See bullets above for narrowing to the latest bake block via line-anchored sed.)
Cross-ReferenceContent
→ See dots-ecsGeneral baking pipeline, IComponentData, SystemAPI
→ See dots-architectureWhen to use SubScene vs runtime spawning