Conversation
|
Generally a cool idea! I think this is a nice architecture. Needs more docs, tests and an example however: Bevy's asset code is already really tricky to learn and change. We should steadily make that better. |
…ergonomics and total functionality.
|
Would it align more with overall design of the asset system if sub-asset processing was specified in meta files? My understanding is each piece of data in a gltf file has a path, so you should be able to specify processing steps and settings per-mesh, per-texture, etc. Thats how I imagined the asset system would work. A loader loads a file, which spawns other loaders/processors. |
UkoeHB
left a comment
There was a problem hiding this comment.
This poor bevy_asset/server/mod.rs file is getting kinda big...
| /// Registers a hook that gives a &mut Asset to the user, along with any arbitrary system | ||
| /// parameters. This runs before the asset is loaded into the world. You can register multiple | ||
| /// hooks. |
There was a problem hiding this comment.
| /// Registers a hook that gives a &mut Asset to the user, along with any arbitrary system | |
| /// parameters. This runs before the asset is loaded into the world. You can register multiple | |
| /// hooks. | |
| /// Registers a system hook that runs after any asset of type `A` is loaded, but before it is added to the world. | |
| /// | |
| /// The system hook's `In` parameter contains an [`AssetWrapper`], which holds a reference | |
| /// to the asset. A panic will occur if the asset wrapper is saved anywhere (the reference is only valid | |
| /// in the system invocation). | |
| /// | |
| /// You can register multiple hooks. |
| /// Exists such that we can determine the type statically for the loading hook from an asset that has an erased type. | ||
| fn load_hook(&mut self, asset_hooks: &mut AssetHooks, world: &mut World); |
There was a problem hiding this comment.
| /// Exists such that we can determine the type statically for the loading hook from an asset that has an erased type. | |
| fn load_hook(&mut self, asset_hooks: &mut AssetHooks, world: &mut World); | |
| /// Runs [`AssetHooks`](AssetHook) for the asset in this container, if any exist. | |
| fn run_hooks(&mut self, asset_hooks: &mut AssetHooks, world: &mut World); |
| fn load_hook(&mut self, asset_hooks: &mut AssetHooks, world: &mut World) { | ||
| asset_hooks.trigger::<A>(self, world); | ||
| } |
There was a problem hiding this comment.
| fn load_hook(&mut self, asset_hooks: &mut AssetHooks, world: &mut World) { | |
| asset_hooks.trigger::<A>(self, world); | |
| } | |
| fn run_hooks(&mut self, asset_hooks: &mut AssetHooks, world: &mut World) { | |
| asset_hooks.run::<A>(self, world); | |
| } |
| } | ||
| #[allow(clippy::unused_unit)] |
There was a problem hiding this comment.
| } | |
| #[allow(clippy::unused_unit)] | |
| } | |
| #[allow(clippy::unused_unit)] |
| } | ||
| /// Safe wrapper around asset pointers to allow for passing into systems. |
There was a problem hiding this comment.
| } | |
| /// Safe wrapper around asset pointers to allow for passing into systems. | |
| } | |
| /// Safe wrapper around asset pointers to allow for passing into systems. |
| fn add_asset_hook<A, Out, Marker, F>(&mut self, f: F) | ||
| where | ||
| A: Asset, | ||
| F: IntoSystem<AssetWrapper<A>, Out, Marker> + Sync + Send + 'static + Clone, |
There was a problem hiding this comment.
| fn add_asset_hook<A, Out, Marker, F>(&mut self, f: F) | |
| where | |
| A: Asset, | |
| F: IntoSystem<AssetWrapper<A>, Out, Marker> + Sync + Send + 'static + Clone, | |
| fn add_asset_hook<A, (), Marker, F>(&mut self, f: F) | |
| where | |
| A: Asset, | |
| F: IntoSystem<AssetWrapper<A>, (), Marker> + Sync + Send + 'static, |
There should not be an output. Also Clone shouldn't be necessary (see fix below).
| pub fn register_asset_hook<A: Asset, Out, Marker>( | ||
| &self, | ||
| hook: impl IntoSystem<AssetWrapper<A>, Out, Marker> + Sync + Send + 'static + Clone, |
There was a problem hiding this comment.
| pub fn register_asset_hook<A: Asset, Out, Marker>( | |
| &self, | |
| hook: impl IntoSystem<AssetWrapper<A>, Out, Marker> + Sync + Send + 'static + Clone, | |
| pub fn register_asset_hook<A: Asset, (), Marker>( | |
| &self, | |
| hook: impl IntoSystem<AssetWrapper<A>, (), Marker> + Sync + Send + 'static, |
| let hooks = self.0.get_mut::<AssetHookVec<A>>().unwrap(); | ||
| hooks.push(Box::new(move |asset, world| { | ||
| let mut system: F::System = IntoSystem::into_system(f.clone()); | ||
| system.initialize(world); | ||
| let asset_wrapper = AssetWrapper::new(asset); |
There was a problem hiding this comment.
| let hooks = self.0.get_mut::<AssetHookVec<A>>().unwrap(); | |
| hooks.push(Box::new(move |asset, world| { | |
| let mut system: F::System = IntoSystem::into_system(f.clone()); | |
| system.initialize(world); | |
| let asset_wrapper = AssetWrapper::new(asset); | |
| let hooks = self.0.get_mut::<AssetHookVec<A>>().unwrap(); | |
| let mut system: F::System = IntoSystem::into_system(f); | |
| let mut initialized = false; | |
| hooks.push(Box::new(move |asset, world| { | |
| if !initialized { | |
| system.initialize(world); | |
| initialized = true; | |
| } | |
| let asset_wrapper = AssetWrapper::new(asset); |
Avoid cloning.
| let loaded_asset: LoadedAsset<A> = asset.into(); | ||
|
|
||
| let erased_loaded_asset: ErasedLoadedAsset = loaded_asset.into(); |
There was a problem hiding this comment.
| let loaded_asset: LoadedAsset<A> = asset.into(); | |
| let erased_loaded_asset: ErasedLoadedAsset = loaded_asset.into(); | |
| let loaded_asset: LoadedAsset<A> = asset.into(); | |
| let erased_loaded_asset: ErasedLoadedAsset = loaded_asset.into(); |
| loaded_asset | ||
| .value | ||
| .load_hook(&mut server.data.hooks.write(), world); |
There was a problem hiding this comment.
| loaded_asset | |
| .value | |
| .load_hook(&mut server.data.hooks.write(), world); | |
| loaded_asset | |
| .value | |
| .run_hooks(&mut server.data.hooks.write(), world); |
|
This is a new way to do things that are already possible, without a clear advantage and adding complexity. And as it modify the gltf assets, this would mean a plugin registering hooks for an asset type could break all other use of that asset type |
nicopap
left a comment
There was a problem hiding this comment.
I don't think this is the right way of implementing it. We should first look into improving composability of AssetTransformer before adding this.
In any case, I gave some feedback to help improve this code if it is to be merged.
| pub(crate) hooks: RwLock<AssetHooks>, | ||
| } | ||
|
|
||
| struct TypeMap(hashbrown::HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>); |
There was a problem hiding this comment.
As mentioned, the additions to this file should really be moved in a separate module.
I notice that the key type for TypeMap here is exclusively AssetHookVec<A>. I would suggest replacing the Box<dyn Any> by some erased version of AssetHookVec<A>. Maybe by replacing AssetHookVec<A> with a Vec<SystemId>.
| if !self.0.has::<AssetHookVec<A>>() { | ||
| self.0.set::<AssetHookVec<A>>(Vec::new()); | ||
| } |
There was a problem hiding this comment.
This, followed by the get_mut().unwrap() should be replaced by .entry(value).get_or_default().
| let mut system: F::System = IntoSystem::into_system(f.clone()); | ||
| system.initialize(world); | ||
| let asset_wrapper = AssetWrapper::new(asset); |
There was a problem hiding this comment.
I feel like the initialization logic shouldn't be ran in the closure, but rather in the trigger method. This would reduce code bloat.
|
Triage: has merge conflicts |
|
I think the general consensus by the asset adjacent people was that this doesn't fit into the current asset system well. If that has changed then I would love to take this to completion! |
|
Yeah, I think this solves a very real problem but needs to be taken back to the drawing board. Closing for now, but I'd like to see another design in this space. |
Objective
Need to perform transformations on gLTFs and other assets in the future, in order to parse it properly and spawn entities, components based on the data before it's loaded.
Solution
This pr allows any third party crate to register multiple transformations to apply to assets before they actually get loaded.
Changelog
Added
fn register_asset_hook<A: Asset, Out, Marker>(
&mut self,
hook: impl IntoSystem<AssetWrapper, Out, Marker> + Sync + Send + 'static + Clone,
) ;
to register asset hooks.