On this page
Offline Conversion and Component Support
Read Supported Boundaries and Unsupported Operations first. Build success does not reproduce every Prefab component or behavior.
This guide covers Tools > ECSAnimator > Convert Character. Complete installation and Settings first.
1. Generated assets
Saved character Prefab + Controller + meshes/materials > Build > CharacterRuntimeAsset > runtime Entity spawning.
Build samples bones, compiles the state machine and writes character assets in the Editor. It does not spawn a scene character or turn every GameObject component into an ECS component. CharacterRuntime creates animation-root and rendering Entities from the EntityDesc. The original Animator, bone GameObjects and gameplay MonoBehaviours do not continue running. Conversion does not invoke custom Bakers and is not a general SubScene/Entity Prefab exporter.
| Asset/object | Role |
|---|---|
| Source Prefab, Controller, clips, meshes, materials and textures | Authoring inputs maintained in your own asset directories |
| Convert Preset | Stores Prefab, product identity, output directory and Animator selection |
| <PrefabName>_EntityDesc.asset (CharacterRuntimeAsset) | Defaults beside the source Prefab; single loading/spawning entry; embeds animation bytes, derived meshes and materials |
| Runtime Entity | Spawned during Play and released through the runtime lifecycle, not an offline .prefab |
For example, Assets/Characters/Soldier.prefab produces Assets/Characters/Soldier_EntityDesc.asset. Expand it in Project to inspect animation data named after the selected Controller and meshes/materials with their source names. The animation is compiled state-machine/parameter/blending/pose data, not an editable AnimatorController or AnimationClip copy. New builds do not create a separate Payload.bytes. Textures and Shaders remain ordinary external references.
You may move EntityDesc through Unity's Project window to another Assets directory. Preserve its GUID, metadata and _EntityDesc.asset suffix. Rebuilding the same source/Product Key finds and updates the moved entry. Do not duplicate entries with the same Product Key: CVT009_ENTITY_DESC_AMBIGUOUS requires a unique published entry.
ArtifactV4 contains immutable Editor snapshots and recovery ownership. New descriptors do not load runtime data from that directory. When output is in Resources, snapshots/recovery live under the corresponding Editor/ECSAnimatorGenerated directory, avoiding duplicate runtime data. Moving the published entry does not require moving snapshots, but retaining rebuild/recovery capability requires the original build records and sources. The legacy Payload field and external Payload.bytes reader have been removed. Existing outputs must contain embedded Animation Data; rebuild older external-payload assets from their source Prefabs before upgrading. Use Unity dependency export to distribute the descriptor, textures, Shaders and required plugin code.
Distributed demo Prefabs and descriptors are together in their Resources/ECSAnimator directories. Presets remain in Authoring/source directories with empty Output Root. Runtime loads the descriptor directly by its current Resources path. Loading and instantiating the source GameObject instead would create an ordinary GameObject/Animator.
Distributed samples omit another project's local Editor snapshots. For your first rebuild, copy the source Prefab to a new name, create a preset with a new unique Product Key and leave Output Root empty. Keep your newly generated snapshots for later rebuilds. Prebuilt EntityDesc assets run without conversion; imported output is not your project's original recovery history.
Your resource manager loads the generated CharacterRuntimeAsset directly. Resources.Load<CharacterRuntimeAsset>("Characters/Soldier_EntityDesc") loads Resources/Characters/Soldier_EntityDesc.asset; omit the extension. If you move it, update Resources/Bundle paths or loader addresses. Unity object references remain valid when the GUID is preserved. Source Prefabs in Resources also enter builds, so retain them there only when needed.
There is no generated character Template asset, default-scale shell or gameplay-alias table. Spawn scale belongs to CharacterSpawnRequest; the Inspector spawner uses its Transform's positive uniform scale. Animation clients use exact compiled keys, as described in Animation integration.
Updating older integrations
Load or assign CharacterRuntimeAsset (*_EntityDesc.asset) directly, then call TryPrepare. The transient prepared handle is now CharacterPreparedAsset, whose Asset property exposes the descriptor. CharacterTemplateAsset, CharacterGameplayAlias and TryEnsureTemplate were removed. Update old C# type names, Inspector references and Resources/Bundle paths; keep stable Addressables addresses pointed at the descriptor. Replace friendly animation aliases with the actual Controller parameter names, layer names or full exported state keys. Existing EntityDesc animation data does not need rebaking solely for this API change.
2. Prepare inputs
- Create and save a .prefab. An FBX model asset or temporary scene object is not a direct conversion-window input.
- Assign a valid AnimatorController; Humanoid needs a valid matching Avatar. One Animator is recommended. With several, a valid Animator Path wins; otherwise the first in hierarchy order, including inactive objects, is selected. Others are omitted with diagnostics. Split independent animations into complete single-Animator Prefabs when needed; selection does not assemble assets or filter subtrees.
- Provide at least one SkinnedMeshRenderer with valid bones, bind poses and readable mesh. Enable Read/Write Enabled. Position, Normal, Tangent and UV0 must be complete; submeshes use triangles.
- Assign ECSAnimator/Lit or complete the External Shader integration. Ordinary URP/Lit is not adapted automatically.
- Review the component table. Unsupported components may remain in the source and are omitted with diagnostics. To preserve their effects, manage them separately in gameplay. Inactive children are still discovered.
- Save all inputs. Start with one Idle/Run Controller and Speed parameter, then add layers, sockets and LOD.
3. Conversion window
- Open Tools > ECSAnimator > Convert Character and assign Character Prefab. Preview updates automatically; use Refresh Preview after changes.
- For reusable settings, create Assets > Create > ECSAnimator > Convert Preset, then assign Preset (optional).
| Preset field | Rule |
|---|---|
| Prefab | Saved .prefab; the preset's Prefab is authoritative when a preset is selected |
| Product Key | Stable unique identity, such as game.hero.knight; an empty field derives a default from the source |
| Output Root | Optional Assets directory, such as Assets/Game/Generated/Characters; empty uses the source directory |
| Animator Path | Relative path such as Model/Rig. Empty selects the first Animator. An invalid path warns and falls back to the first. It does not exclude other renderers, sockets or LOD subtrees. |
- Read each finding's code, object path and description. The API categories are:
| Category | Build | Action |
|---|---|---|
| Supported | Allowed | Continue; full sampling/validation may still find errors |
| Ignored | Allowed without another confirmation | Inspect omitted Animators/components and replace required gameplay behavior |
| NeedsVerification | Allowed | External structure passed; test actual rendering and the target platform |
| NeedsHook | Blocked | Complete Shader integration, then preview again |
| Rejected | Blocked | Repair inputs; do not remove validators or edit generated data |
- Click Build. Completion selects the EntityDesc and reports its path and any omissions.
- Test default animation through the Inspector route below before connecting parameters. Preview is not a final build result.
Mesh/static-skin and state-arena byte figures cover only those data categories, not total RAM/VRAM. The window has no cancellation button; custom Editor callers can supply CancellationToken. Never mutate sources/presets during a build.
4. Spawn before connecting gameplay
Add CharacterSpawnerBehaviour to an empty GameObject:
| Field | Setting |
|---|---|
| Entity Desc | Generated <PrefabName>_EntityDesc.asset |
| Count / Spacing | Start with one; larger counts use XZ grid spacing |
| World Selection / World Name | DefaultWorld for one live World; exact unique NamedWorld otherwise |
| Destroy On Disable | Normally on; disabling it retains characters when the component is disabled, but destroying the GameObject still cleans up |
Position, rotation and positive uniform scale determine initial placement. Moving the Spawner after Play does not move spawned Entities. This component does not read keyboard input or set parameters; it plays the Controller's default state. Use SimpleCharacterExample for Speed and movement, rather than attaching two spawners.
5. Component and resource support
“Exported” means data is extracted, not that UnityEngine components remain on the Entity.
| Source | Handling | Scope |
|---|---|---|
| Transform / bone hierarchy | Exported | Skeleton, local poses and required transforms; no script-addressable GameObject per bone |
| Animator | Skeletal presentation | Selected Controller/Avatar sampled offline; no runtime Animator instance |
| AnimatorController | Exported | Parameters, states, transitions, layers and BlendTrees within the support limits |
| AnimatorOverrideController | Conditional | One direct override layer with replacement and null/base fallback; no nested chain |
| AnimationClip / Avatar / AvatarMask | Conditional | Generic/Humanoid skeletal sampling and layer masks; no runtime Avatar retargeting |
| SkinnedMeshRenderer | Exported | Mesh and material slots; at most 256 skeleton nodes and 6 influences per vertex; BlendShape meshes rejected |
| CharacterAttachmentAuthoring | Exported | Semantic key, owner bone and relative transform |
| MeshRenderer + MeshFilter | Conditional | Rigid attachment under the nearest valid socket marker, exactly one MeshFilter/sharedMesh, owner bone in the character; converted to single-bone skinning |
| LODGroup | Conditional | At most one enabled group with exported levels, at most 8 retained levels; omitted renderers/levels are filtered |
| Material / Shader / Texture | Conditional | Built-in Lit or adapted External; material snapshots, ordinary texture references, opaque/cutout only |
| Renderer layer, renderingLayerMask, shadows and motion | Supported settings retained | External uses Camera motion. MaterialPropertyBlock on exported renderers is rejected; omitted renderers are excluded from that check |
| Light Probe Usage / Probe Anchor | Ignored | No per-instance probes; global ambient remains |
| Apply Root Motion | Omitted | Gameplay owns LocalTransform |
| StateMachineBehaviour | Omitted | Scripts are not executed during sampling or runtime |
| IK Pass / Foot IK | Omitted | No runtime IK; offline Humanoid retargeting may influence sampled poses |
| BlendShape, material/visibility/object-reference curves | Rejected | Non-skeletal animation is not silently discarded |
| Unmarked MeshRenderer, ParticleSystemRenderer, TrailRenderer, LineRenderer, SpriteRenderer | Omitted with diagnostics | No rendering, mesh/material data or LOD references; source objects remain |
| ParticleSystem, colliders, Rigidbody, CharacterController, NavMeshAgent, audio, lights, cameras, custom MonoBehaviour | Not exported | No automatic gameplay conversion or Baker invocation |
| Cloth, Animation Rigging and runtime constraints | No corresponding runtime system | Do not rely on source components continuing to simulate; External also explicitly rejects Cloth |
| Custom IComponentData / IBufferElementData | Code extension | Declare explicitly through prototype/spawn extension points |
6. Attachments, equipment and LOD
6.1 Choose an attachment route
| Goal | Route | Ownership |
|---|---|---|
| Fixed sword/shield as part of a character | Build MeshRenderer + MeshFilter under a socket marker | Geometry belongs to the character artifact; changes require a rebuild |
| Particle, audio, UI or GameObject following a bone | Read semantic socket poses; reuse CharacterAttachmentFollower | Gameplay creates, pools and destroys the external object |
| Independent rigid ECS equipment | CharacterRigidEquipmentAttachment and its system | Gameplay owns equipment Entities, rendering, swaps and destruction |
Sockets are named bone anchors, not an inventory or automatic equipment system. A baked-in weapon plus an external weapon produces two copies. Remove fixed geometry and rebuild before switching to dynamic equipment.
6.2 Author sockets
- In the saved character Prefab, create or mark an object such as WeaponSocket near the required bone. Set its local placement.
- Add CharacterAttachmentAuthoring with a stable, unique Semantic Key such as attachment.weapon. This is a lookup key, not a hierarchy path.
- Assign an actual in-character Owner Bone. The exported offset is relative to that bone; keep transforms valid and nondegenerate.
- Save, refresh Preview and rebuild.
- Load the new EntityDesc and Prepare again; existing instances/bindings do not acquire new sockets automatically.
Example keys are TownGuard's attachment.right.sword and attachment.left.shield, CrossbowGuard's attachment.right.crossbow, and Quick Start's attachment.weapon. They do not apply automatically to arbitrary models.
6.3 Build fixed geometry
Place a weapon with MeshRenderer and exactly one MeshFilter on or below the marker. The MeshFilter needs sharedMesh; the nearest marker must reference a valid owner bone. Mesh/material requirements still apply. The converter generates single-bone rigid skinning, spawned and destroyed with the character.
An existing SkinnedMeshRenderer uses the normal skinned path. The current sword/shield/crossbow examples use single-bone SMRs with semantic sockets; no conversion to MeshRenderer is required merely to declare a socket.
Changing fixed geometry requires changing the source and rebuilding. Unsupported renderers, including inactive particles, are omitted. Use external following for their effects.
6.4 Follow with a GameObject, particle or audio object
Reuse CharacterAttachmentFollower:
- Import Quick Start and add the follower to a separately created effect/prop root, outside the character being converted.
- Set its real Attachment Key. Local Position / Local Euler Angles add an offset on top of the authored socket; do not duplicate the original offset.
- After TrySpawn succeeds, call follower.TryFollow(runtime, prepared, spawned) with the same World and Prepare generation. Check the return value; adding the component alone does not discover a character.
- LateUpdate reads TryGetAttachmentPose and copies position/rotation. A newly spawned character may not yet have a valid published pose; wait for normal World updates and retry.
- Call StopFollowing before changing targets, destroying the character or unloading. Gameplay must hide, pool or destroy the external object.
This sample copies position/rotation, not full scale/shear. Handle nonuniform/negative scale or full-matrix needs separately. External objects are not automatically converted to ECS.
For custom code, resolve once with runtime.TryResolveAttachment(prepared.Bindings, key, out attachment), then read runtime.TryGetAttachmentPose(spawned.SpawnId, attachment, out pose) on the main thread. pose.LocalToWorld already includes the character root. The offset overload composes root × socket pose × localOffset; do not multiply the root again. Poses come from the latest committed evaluation, which may be older than the current frame under animation LOD.
6.5 Independent rigid ECS equipment
- Create a renderable rigid root Entity with LocalToWorld and no Parent. Gameplay supplies mesh/material and rendering components.
- Resolve the current character Entity through runtime.TryResolve(spawned.SpawnId, out characterEntity). If another API returns a deferred identity, wait for its accepted result; never bind a placeholder.
- Call CharacterRigidEquipmentAttachment.TryCreate(characterEntity, prepared, key, localOffset, out binding), then add or update the binding on the equipment. The prepared object must match that character's artifact.
- CharacterRigidEquipmentAttachmentSystem writes the equipment's complete LocalToWorld after evaluation. Give it sole transform ownership. Optional PostTransformMatrix is appended once; do not premultiply it into localOffset.
- Gameplay removes/destroys old equipment before binding replacements, and cleans equipment before the character. Invalid character/pose data does not automatically destroy equipment; the previous transform can remain.
This supports one rigid ECS root, not Parent-based hierarchies, child render trees, skinned equipment or independent Animators. It does not merge artifacts or guarantee shared character draw calls. Demo17 has local Windows D3D11 Player evidence for equipment rendering, swaps, automatic/manual LOD and visible Idle, plus Unity 2022.3.1f1 Editor checks. It does not qualify mobile or arbitrary equipment structures. See the attachment API.
Missing sockets usually indicate unsaved/unbuilt markers or wrong keys. Wrong placement suggests an owner-bone or duplicated-offset problem. First-frame failures require a published pose. Leftover props indicate missing gameplay cleanup.
Runnable example: import Demos and open 17_ModularEquipment/Scenes/ModularEquipment.unity. The UI equips/unequips sword and shield independently or together and triggers attacks. Earlier full-character demos are retained.
Its independent Body.prefab removes sword/shield renderers but retains sockets and repairs LOD references. Sword/Shield/Crossbow Prefabs contain three rigid mesh levels with one MeshFilter/MeshRenderer per level and a shared URP/Lit material, without Animators. The sample loads mesh/material resources and creates Entities Graphics equipment, not more baked character state machines.
When extracting rigid equipment from a single-bone SMR, bake the bind-pose correction into socket-local space and preserve UVs/normals/tangents/materials. Copying sharedMesh alone need not preserve placement. Wait for the first valid socket pose before showing new equipment. Unequipping destroys only that item. During shutdown, clean equipment, dispose the client, destroy the scope, release prepared data and wait for Released before unloading dependencies.
The sample supports a single root, submesh and material. See Demo17. It does not automatically split multiple Animators, save child-character references or recursively assemble assets. Animator Path selects one Controller, while discovery still traverses the full Prefab.
Equipment LOD: add CharacterRigidEquipmentLod with FirstMeshIndex=0 and MeshCount=3 to follow the character's CharacterLodSelection. Store meshes contiguously in one RenderMeshArray in LOD order, keep material/submesh fixed and make RenderBounds cover all levels. The system writes only when the index changes; it does not recreate Entities, rebind bones or load assets. Missing later levels clamp to the last available mesh. Hidden characters hide equipment.
Apply the current Level/Hidden immediately when equipping. Entities Graphics AddComponents needs a valid mesh, so the sample initializes valid components then applies the current mesh/hidden state within the same creation flow. Load and retain all meshes/materials before use. Equipment's source LODGroup supplies ordered meshes; runtime follows the body level rather than computing another distance.
For manual handling, Demo17's OnLodChanged(int level, bool hidden) observes one character on the main thread and notifies initially and when Level/Hidden changes. It is not a global managed broadcast. Remove CharacterRigidEquipmentLod before manual writes to MaterialMeshInfo. Re-add it for automatic mode. The UI tests far/hidden re-equipping. Model LOD notifications do not describe animation LOD; inspect CharacterUpdateBudget separately. Clean subscriptions and equipment before destroying the body. Automatic equipment LOD hides orphaned equipment but does not destroy it.
Demo17's body reference size is approximately 1.19 m with thresholds 0.4/0.2/0.01. At 45-degree FOV and lodBias=1, distances of 3/6/12 m demonstrate LOD0/1/2, and 250 m demonstrates Hidden. Demo18's full characters have different bounds; do not reuse fixed distances blindly.
6.6 LOD
Unsupported renderer references are omitted. Levels containing only omitted renderers are removed; retained levels keep their source thresholds and are renumbered from zero. The last retained threshold controls hiding. A group with no exported levels is ignored; with no valid group, all exported meshes form one level. Genuine empty levels, null/out-of-Prefab references and invalid retained geometry/thresholds are still rejected.
Use one enabled LODGroup, Fade Mode None, Animate Cross-fading off and Fade Transition Width zero. Retained thresholds must be strictly decreasing in (0,1]. Each level needs real renderers; do not reuse a renderer/mesh as another level. Both total vertices and triangles must decrease at each subsequent level.
The runtime caches Camera.main. Call runtime.TrySetLodCamera(camera, out error) when switching cameras. A newly tagged camera does not automatically replace the cached one.
Demo18 has three mesh levels and four animation-update intervals, with distance buttons and close-up inspection. Model LOD uses screen-relative height; animation LOD uses distance. Below the last model threshold the character is hidden. There is no crossfade, runtime decimation or bone-count LOD.
Configure animation LOD during Prepare:
var lod = new CharacterSimulationLodSettings(true, 0, 1, 0,
8, 16, 30, .5f, 1, 2, 4, 8);
if (!runtime.TryPrepare(entityDesc, lod, out var prepared, out var error))
throw new System.InvalidOperationException(error);
This uses local reference point (0,1,0), distance boundaries 8/16/30 m, 0.5 m hysteresis and evaluation every 1/2/4/8 frames. These are not fixed Hz. Accumulated time is consumed at the next evaluation; sockets retain the last committed pose. First Prepare establishes shared settings for a World/Product Key. Conflicting explicit settings while live are rejected. The overload without settings reuses loaded settings, or the baked default (currently every frame) on first load. Destroy/release all users and wait for Released before preparing a new policy.
Conversion exports supported data, not individual GameObject components. Valid skins/bones under other Animators can remain but do not receive those independent Controllers; unanimated bones retain sampled baseline poses. Readability, binding, Shader and skeleton-capacity requirements still apply. A Prefab with only omitted components cannot yield a usable character.
7. Custom gameplay components
Define unmanaged ECS data, declare it through ICharacterPrototypeCustomizer, then initialize instances with ICharacterSpawnInitializer. These are runtime Prepare/Spawn extensions, not new offline component converters.
Place these types in a gameplay Runtime asmdef referencing ECSAnimator.Runtime.Product, Unity.Entities and Unity.Collections:
using ECSAnimator.Runtime.Product.ECS;
using Unity.Entities;
public struct GameHealth : IComponentData { public int Value; }
public struct GameDamage : IBufferElementData { public int Value; }
public sealed class GameCharacterPrototype : ICharacterPrototypeCustomizer
{
public PrototypeCustomizationId Id => new PrototypeCustomizationId("game.character", 1);
public void Configure(ref CharacterPrototypeBuilder builder)
{
builder.Add(new GameHealth { Value = 100 });
builder.AddBuffer<GameDamage>();
}
}
public sealed class GameCharacterInitialValues : ICharacterSpawnInitializer
{
public void Initialize(int batchIndex, ref CharacterSpawnValueWriter writer)
{
writer.Set(new GameHealth { Value = 100 + batchIndex });
writer.Buffer<GameDamage>().Clear();
}
}
In the runtime lifecycle, prepare with runtime.TryPrepare(entityDesc, new GameCharacterPrototype(), out prepared, out error), then supply new GameCharacterInitialValues() as the TrySpawn/TrySpawnBatch initializer. Check results and follow normal cleanup on failure. Gameplay queries GameHealth/GameDamage, not render children.
- Add<T> accepts unmanaged IComponentData; AddBuffer<T> accepts unmanaged IBufferElementData. After adding an enableable component, SetEnabled<T> controls its default state.
- Initialize writes only declared types; it cannot change structure.
- Increment the customization Revision whenever Configure output changes, including default values. Identity represents immutable configuration, not a random per-instance value.
- Managed/shared/cleanup components and plugin-owned types, Unity.Transforms/Unity.Rendering, Prefab/Disabled/LinkedEntityGroup and MaterialProperty components are excluded.
- Use SpawnRequest/movement systems for transforms. Custom data does not automatically implement collision, navigation, AI or PhysX-to-Unity-Physics conversion.
8. Rebuilding, recovery and versioning
After changing source animation, Controller, mesh, material or Shader, stop old instances, Build, Prepare again and respawn. Generated materials are snapshots; textures remain live asset references. Do not repair generated materials directly because rebuilding recreates them from source.
The same source/Product Key updates its managed EntityDesc output. Moving EntityDesc preserves its published GUID. Original build roots still own recovery. Moving the source Prefab or changing Product Key/Output Root is a different configuration.
After renaming parameters, layers or states, rebuild and update the exact keys declared by your animation clients. Clients resolve keys during registration; prepare/recreate them after changing compiled data. No alternate-name mappings are generated or retained.
Imported sample output may have distribution-adjusted paths and no local recovery records. Copy the source to a new name, use a unique Product Key and your own empty output location, then replace EntityDesc references. Do not bypass artifact-authority-invalid.
On failure, retain Terminal, stage, diagnostic code/path and Last green preserved. Existing successful output is preserved/restored according to the transaction rules; a first build has no prior success to recover.
V6 is current. Rebuild V4/V5 from source. Owned, matching outputs upgrade only after candidate validation; earlier, damaged or unowned output may reject replacement. Back up sources, presets, descriptors, generated dependencies and metadata together. Never remove recovery records or edit payload digests.
Custom Editor conversion tools call Build synchronously on the Editor main thread. Do not use Player, Task.Run or two Editors building one project concurrently.
9. Runtime resource loading and spawning
A game resource manager can load a generated CharacterRuntimeAsset and use the public runtime APIs without a scene Spawner, fixed Resources path or preconfigured catalog.
EntityDesc is the CharacterRuntimeAsset itself. It embeds animation, meshes and materials; materials still reference textures/Shaders. External Payload.bytes outputs are no longer supported; rebuild them from their source Prefabs. Load and retain the complete dependency chain. This is not a generic JSON Entity description or runtime Prefab conversion.
Resource manager loads CharacterRuntimeAsset and dependencies
> CharacterRuntime.TryGet(target World)
> runtime.TryPrepare(entityDesc)
> runtime.TryCreateScope(capacity)
> runtime.TrySpawn / TrySpawnBatch(prepared, transform, scope, initializer)
> CharacterInstanceHandle / Entity
> Create an animation client and connect gameplay
Check every bool/error. Prepare validates and establishes resources/prototypes; Spawn creates the character. Visible rendering requires later World updates. Reuse prepared data for many instances of the same configuration in one World. Add customizer/initializer arguments for gameplay data.
| Responsibility | Owner |
|---|---|
| Download/load by address, cache, cancellation and retries | Game resource manager |
| Parse artifacts, establish runtime resources, spawn/destroy | ECSAnimator Prepare/Spawn/Destroy/Release |
| Loader handles/reference counts and final Unity asset unloading | Game resource manager, coordinated with plugin retirement |
Resources content must be included through its normal asset layout. AssetBundle/Addressables integrations package and load EntityDesc assets with all dependencies. ECSAnimator does not supply those loaders, downloaders, packagers or reference-counting adapters.
A Windows Editor Play/D3D11 check on September 27, 2026 loaded the former character entry through Resources and a local Windows AssetBundle, spawned/rendered four characters, advanced animation, reached Released and then unloaded the Bundle. Target Players, remote bundles and the complete Addressables route still require their own verification.
On October 3, 2026, the direct EntityDesc route passed Resources and local Windows AssetBundle Editor Play checks: each loader rendered two animated characters for 120 frames, then completed retirement. The RTS addresses also loaded Soldier_EntityDesc and Crossbow_EntityDesc, prepared and released in the Editor asset-database mode; local Addressables content rebuilt successfully. The full RTS scene in Packed Play Mode stopped responding and is not qualified by these checks. Remote delivery, target Players and mobile devices remain outside this result.
After asynchronous loading, call TryGet/Prepare/Spawn on Unity's main thread while the target World remains valid. They are synchronous APIs, not Task.Run work. First Prepare reads and validates data, so budget that cost during loading. If the request was cancelled or its World destroyed, release the loader's hold instead of using a stale World.
Unload order: stop producers/Jobs > dispose clients > destroy equipment/instances/scopes > release prepared data > continue normal World updates until ReleaseState == Released > return the resource manager's load handle.
Pending, Invalid and FaultedRetainedRequiresWorldRebuild are not successful retirement. Release's bool reports the request outcome, not completed GPU retirement. Retain dependencies while any other character, prepared resource or World uses them. Never force-unload meshes/materials/textures/Bundles first.
A World cannot prepare another Artifact Digest with the same Product Key while an old generation remains live. It reports “A different artifact generation is already live for this product.” Retire all old users before preparing the new generation; seamless hot replacement is not promised.