Conversation
917c1a9 to
8448f5f
Compare
|
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! 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
|
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! 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. |
|
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! 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
|
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! 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. |
|
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! 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. |
|
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! 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. |
|
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! 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. |
|
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! 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. |
Trashtalk217
left a comment
There was a problem hiding this comment.
This review was kinda pushed to the back of my queue, so I'm sorry if it's late. I have two things I'd like to see addressed:
- Use Mesh::from, over .into() as it makes debugging better
- Eventually merge AssetCommands and Commands. I think it's technically possible, and the API is workable. Just not in this PR.
| Some(task_data) => { | ||
| if let Some(mut image) = images.get_mut(image_h) { | ||
| *image = task_data.image; | ||
| ***image = task_data.image; |
There was a problem hiding this comment.
Triple Deref is a bit cursed.
There was a problem hiding this comment.
Fixed this by manually implementing Deref/DerefMut and DetectChanges/DetectChangesMut to point directly to the inner A! Much better! This comment made me realize I could do that lol
|
|
||
| let embedded = EmbeddedAssetRegistry::default(); | ||
|
|
||
| let handle_provider = app.world().resource::<AssetHandleProvider>().clone(); |
There was a problem hiding this comment.
What does this do? What does it replace?
There was a problem hiding this comment.
Previously, each Assets resource would have its own handle provider, since each type had its own storage.
Now that we have one storage (the World), we need a shared handle provider that all assets use.
Put another way, previously we were initializing a handle provider per asset type in init_asset (through the Assets constructor). Now since our storage is shared, we don't need a handle provider per-type, we need one global handle provider.
As for why we need to clone here, it's because the AssetServer needs to be able to create handles remotely. Previously in init_asset we registered the asset type to the AssetServer, which would clone the type's handle provider.
| let embedded = EmbeddedAssetRegistry::default(); | ||
|
|
||
| let handle_provider = app.world().resource::<AssetHandleProvider>().clone(); | ||
| let uuid_map = app.world().resource::<AssetUuidMap>().clone(); |
There was a problem hiding this comment.
Previously, the Assets resource stored a mapping from UUID to Asset. When you lookup a UUID handle, it would go to the Assets resource, go into the UUID storage, lookup the UUID, and give you the asset.
Now, we have the AssetUuidMap which stores a mapping from UUID to EntityHandle. So now when you lookup a UUID handle, it first goes to the AssetUuidMap, finds the EntityHandle, then lookups the Entity, and gives you the asset.
As for why we need to clone here, it's because the AssetServer needs an instance internally to resolve some handles.
| pub(crate) drop_receiver: Receiver<DropEvent>, | ||
| pub(crate) type_id: TypeId, | ||
| #[derive(Component)] | ||
| pub struct AssetSelfHandle(pub(crate) Weak<StrongHandle>); |
There was a problem hiding this comment.
Some docs would be nice here.
There was a problem hiding this comment.
Done! This definitely needed some docs haha.
|
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! 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. |
Co-authored-by: Trashtalk217
andriyDev
left a comment
There was a problem hiding this comment.
@Trashtalk217 I've replaced all the instances of .into() with *::from. It's possible I've missed one or two, but I literally went through all .into() instances lol.
As for combining Commands and AssetCommands, the regression that causes is way too big. Maybe if everything moves to BSN this won't be a problem? I'm extremely skeptical though.
| let embedded = EmbeddedAssetRegistry::default(); | ||
|
|
||
| let handle_provider = app.world().resource::<AssetHandleProvider>().clone(); | ||
| let uuid_map = app.world().resource::<AssetUuidMap>().clone(); |
There was a problem hiding this comment.
Previously, the Assets resource stored a mapping from UUID to Asset. When you lookup a UUID handle, it would go to the Assets resource, go into the UUID storage, lookup the UUID, and give you the asset.
Now, we have the AssetUuidMap which stores a mapping from UUID to EntityHandle. So now when you lookup a UUID handle, it first goes to the AssetUuidMap, finds the EntityHandle, then lookups the Entity, and gives you the asset.
As for why we need to clone here, it's because the AssetServer needs an instance internally to resolve some handles.
|
|
||
| let embedded = EmbeddedAssetRegistry::default(); | ||
|
|
||
| let handle_provider = app.world().resource::<AssetHandleProvider>().clone(); |
There was a problem hiding this comment.
Previously, each Assets resource would have its own handle provider, since each type had its own storage.
Now that we have one storage (the World), we need a shared handle provider that all assets use.
Put another way, previously we were initializing a handle provider per asset type in init_asset (through the Assets constructor). Now since our storage is shared, we don't need a handle provider per-type, we need one global handle provider.
As for why we need to clone here, it's because the AssetServer needs to be able to create handles remotely. Previously in init_asset we registered the asset type to the AssetServer, which would clone the type's handle provider.
| pub(crate) drop_receiver: Receiver<DropEvent>, | ||
| pub(crate) type_id: TypeId, | ||
| #[derive(Component)] | ||
| pub struct AssetSelfHandle(pub(crate) Weak<StrongHandle>); |
There was a problem hiding this comment.
Done! This definitely needed some docs haha.
Trashtalk217
left a comment
There was a problem hiding this comment.
For future reference. Merging Commands and AssetCommands would result in the following code:
commands.spawn((
// BORROWING COMMANDS TWICE MUTABLY
Mesh3d(commands.spawn_asset(Mesh::from(Cuboid::default()))),
));which would break. However, I believe that we can do some API trick (probably with closures) that would allow this to be more manageble. Perhaps with some shortcuts for specific common operations. Also,
let a = Mesh3d(commands.spawn_asset(Mesh::from(Cuboid::default())));
commands.spawn(a);Is really not that bad.
That all being said, given that there are also some technical hurdles and the current API is already a big improvement, I won't dwell on it any longer. As far as I'm concerned it's good to merge.
(After fixing merge conflicts)
Objective
Solution
Assetsresource.AssetHandleProviderinto a resource that can create any kind of handle.AssetCommandssystem param that spawns an entity and creates a handle for it.AssetServerhold aRemoveAllocatorand remote-allocate an entity when loading assets.AssetsandAssetsMutsystem params to replicate the oldAssetsAPI.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::Unusedwhen 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:
Assets::get_strong_handlehas different behaviour to one fromAssetServer::load. #20651: there's now no difference between handles created from the asset server orAssets. This also simplifies our handle dropping stuff.AssetUuidMap! Maybe no one will use this, but it's cool we can do this now!Some concerns with this feature/implementation.
AssetServer::loadorAssets::get_strong_handlefor 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 byasset_server_managed. #22261 (comment), it seems we are ok with that. This could be something to bring back in the future.Commandsparams: oneCommandsand anotherAssetCommands. Unfortunately these are applied in param order, not the order that commands are enqueued. So if the order isCommandsthenAssetCommands, and if a user spawns an asset throughAssetCommands, 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::loadreturns aHandle::Entitywhich is a remote-allocated entity. It only gets actually allocated duringhandle_internal_asset_eventsinPreUpdate. I'm not entirely sure what the behavior is here with every feature: I assume that trying to access this entity (e.g., throughWorld::get_entity_mut) before it's actually allocated will return an error (or for panicking APIs, panic). This could be future work: we could splitAssetServerintoAssetServerSystemParam (which would allow us to not remote-allocate the entity), andRemoteAssetServer(which would remote-allocate the entity).AssetEventand 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 deleteAssetEventin the future and replace it with change detection / observers. So this fix is duct tape, but that's ok.impl Into<A>. I've done this since we now have untypedAssetCommands::spawn_assetandworld.spawn_asset: we can't deduce the type ofAfrom this. So in many cases, we'd need to explicitly specify the asset type which seems silly especially when you doasset_commands.spawn_asset::<StandardMaterial>(StandardMaterial { .. }). This has the effect that things likeCuboidneed to be converted into aMesh, either through.into()orMesh::from.Testing