Skip to content

Assets as entities v0#22939

Open
andriyDev wants to merge 13 commits intobevyengine:mainfrom
andriyDev:asset-v1
Open

Assets as entities v0#22939
andriyDev wants to merge 13 commits intobevyengine:mainfrom
andriyDev:asset-v1

Conversation

@andriyDev
Copy link
Contributor

@andriyDev andriyDev commented Feb 13, 2026

Objective

Solution

  • Remove the Assets resource.
  • Turn AssetHandleProvider into a resource that can create any kind of handle.
  • Create an AssetCommands system param that spawns an entity and creates a handle for it.
  • Make AssetServer hold a RemoveAllocator and remote-allocate an entity when loading assets.
  • Create a system to listen for handle drop events and despawn the entity.
  • Create Assets and AssetsMut system params to replicate the old Assets API.

I've done my best to keep this PR focused on the bare minimum for assets as entities. This also means I've had to do some weird back-porting. For example, I've needed to create a type ID to "sender" map to be able to send the appropriate AssetEvent::Unused when despawning an asset. In the future, this should be replaced by just an event, and then we don't need the type ID at all.

Some features we get for free:

  • Always strong: handles are now always strong in essence! UUID handles are now just looked up just before accessing the asset data, but this lookup map stores the asset handle to the actual entity. So assigning a handle to a UUID essentially just treats that UUID as a permanent reference.
  • Solves Dropping a handle from Assets::get_strong_handle has different behaviour to one from AssetServer::load. #20651: there's now no difference between handles created from the asset server or Assets. This also simplifies our handle dropping stuff.
  • We can load UUID assets now by loading an asset and then assigning that handle to a UUID in the AssetUuidMap! Maybe no one will use this, but it's cool we can do this now!

Some concerns with this feature/implementation.

  • We can no longer "revive" an asset once its handles are dropped. Previously, if all handles for an asset are dropped, but you call AssetServer::load or Assets::get_strong_handle for that asset in the same frame, the asset won't be dropped and you will now have new handles to that asset. Based on discussion in Fix handles being split by asset_server_managed. #22261 (comment), it seems we are ok with that. This could be something to bring back in the future.
  • We can no longer access assets mutably after adding them in the same system. Since assets need to be spawned in order to query them, and spawning (in a normal system) is deferred, we can't really do this. I think this is just a permanent limitation.
  • Systems can now reasonably have two Commands params: one Commands and another AssetCommands. Unfortunately these are applied in param order, not the order that commands are enqueued. So if the order is Commands then AssetCommands, and if a user spawns an asset through AssetCommands, then enqueue a command that uses that entity, the entity will not have been spawned yet! This is discussed more in Shared State for System Param #22885. It's probably not a big deal, but if we care about removing this footrake, we can solve Shared State for System Param #22885.
  • AssetServer::load returns a Handle::Entity which is a remote-allocated entity. It only gets actually allocated during handle_internal_asset_events in PreUpdate. I'm not entirely sure what the behavior is here with every feature: I assume that trying to access this entity (e.g., through World::get_entity_mut) before it's actually allocated will return an error (or for panicking APIs, panic). This could be future work: we could split AssetServer into AssetServer SystemParam (which would allow us to not remote-allocate the entity), and RemoteAssetServer (which would remote-allocate the entity).
  • I've had to re-implement AssetEvent and the implementation is kind of rough. UUID handles in particular are not the most reliable. Changing which asset entity a UUID points to may break things - however this API wasn't even possible before so it's unlikely people will use it. In addition, we expect to delete AssetEvent in the future and replace it with change detection / observers. So this fix is duct tape, but that's ok.
  • You can no longer add assets with things that impl Into<A>. I've done this since we now have untyped AssetCommands::spawn_asset and world.spawn_asset: we can't deduce the type of A from this. So in many cases, we'd need to explicitly specify the asset type which seems silly especially when you do asset_commands.spawn_asset::<StandardMaterial>(StandardMaterial { .. }). This has the effect that things like Cuboid need to be converted into a Mesh, either through .into() or Mesh::from.

Testing

  • I ran a handful of examples and they still seem to work! I tested the solari example also which tests both the changes made to solari, and also the changes made to the text pipelines (since that example contains rendered text). The testbed_ui examples also showed how necessary (for the time being) AssetEvents for UUID assets are.
  • Asset tests all pass.

@andriyDev andriyDev added C-Feature A new feature, making something new possible A-Assets Load files from disk to use for things like images, models, and sounds M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Feb 13, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in Assets Feb 13, 2026
@andriyDev andriyDev force-pushed the asset-v1 branch 7 times, most recently from 917c1a9 to 8448f5f Compare February 14, 2026 01:44
@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

1 similar comment
@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

1 similar comment
@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

.read()
.get(&type_id)
.and_then(|inner| inner.uuid_to_handle.get(&uuid))
.map(|value| value.0.entity)

Check failure

Code scanning / CodeQL

Cleartext logging of sensitive information High

This operation writes
... .get(...)
to a log file.
@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22939

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@andriyDev andriyDev marked this pull request as ready for review February 15, 2026 00:51
@andriyDev andriyDev added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Feb 15, 2026
@andriyDev
Copy link
Contributor Author

For some reason, CodeQL thinks logging UUIDs passed into resolve_entity is sensitive information? I think we can ignore that.

I'm also not sure exactly why there's a rendering difference. I believe it is a boundary condition of some kind for texture atlases. Some discussion about it here: https://discord.com/channels/691052431525675048/743663673393938453/1472354467105083452 The diffs are very tiny though, and afaik this seems to be an ordering problem on main.

@greeble-dev
Copy link
Contributor

Re the rendering difference, I had the exact same issue with that one example in another PR: #18465 (comment). Went away without me changing anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Assets Load files from disk to use for things like images, models, and sounds C-Feature A new feature, making something new possible D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide M-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

2 participants