Skip to content

Commit

Permalink
Merge pull request #41 from MrGVSV/better-config
Browse files Browse the repository at this point in the history
Add custom configs and custom loaders
  • Loading branch information
MrGVSV authored May 11, 2023
2 parents 0913030 + fe9a207 commit b6c2072
Show file tree
Hide file tree
Showing 50 changed files with 1,074 additions and 426 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ serde_yaml = { version = "0.9", optional = true, default-features = false }

[dev-dependencies]
ron = "0.8"
serde_yaml = "0.9"
bevy = "0.10.1"
bevy_prototype_lyon = "0.8.0"
trybuild = "1.0.71"
Expand All @@ -119,6 +120,16 @@ name = "basic_schematic"
path = "examples/basic_schematic.rs"
required-features = ["ron", "auto_name", "custom_schematics", "bevy_sprite"]

[[example]]
name = "custom_config"
path = "examples/custom_config.rs"
required-features = ["ron", "auto_name"]

[[example]]
name = "custom_loader"
path = "examples/custom_loader.rs"
required-features = ["ron", "auto_name"]

[[example]]
name = "custom_schematic"
path = "examples/custom_schematic.rs"
Expand Down
3 changes: 3 additions & 0 deletions assets/examples/custom_config/Player.prototype.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(
name: "Player"
)
11 changes: 11 additions & 0 deletions assets/examples/custom_loader/Player.custom.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Player
schematics:
custom_loader::Player:
# Comment out the `Health` component below to have this prototype
# be rejected by our custom loader.
custom_loader::Health:
- 100
# Comment out the `Mana` component below to have a default instance
# of it be inserted by our custom loader.
custom_loader::Mana:
- 100
36 changes: 17 additions & 19 deletions bevy_proto_backend/src/children/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,61 @@ use std::path::Path;

use bevy::asset::{AssetIo, Handle, LoadedAsset};

use crate::load::ProtoLoadContext;
use crate::load::{Loader, ProtoLoadContext};
use crate::path::{ProtoPath, ProtoPathContext};
use crate::proto::Prototypical;

/// A helper struct for properly building out a [prototype's] children.
///
/// [prototype's]: Prototypical
pub struct ProtoChildBuilder<'ctx, 'load_ctx, T: Prototypical> {
pub(crate) context: ProtoLoadContext<'ctx, 'load_ctx, T>,
child_count: usize,
pub struct ProtoChildBuilder<'ctx, 'load_ctx, T: Prototypical, L: Loader<T>> {
pub(crate) context: ProtoLoadContext<'ctx, 'load_ctx, T, L>,
}

impl<'ctx, 'load_ctx, T: Prototypical> ProtoChildBuilder<'ctx, 'load_ctx, T> {
pub(crate) fn new(context: ProtoLoadContext<'ctx, 'load_ctx, T>) -> Self {
Self {
context,
child_count: 0,
}
impl<'ctx, 'load_ctx, T: Prototypical, L: Loader<T>> ProtoChildBuilder<'ctx, 'load_ctx, T, L> {
pub(crate) fn new(context: ProtoLoadContext<'ctx, 'load_ctx, T, L>) -> Self {
Self { context }
}

/// Add the given child to the parent.
pub fn add_child(&mut self, mut child: T) -> Result<Handle<T>, T::Error> {
let deps = self.context.preprocess_proto(&mut child)?;
pub fn add_child(&mut self, child: T) -> Result<Handle<T>, L::Error> {
let (child, meta, deps) = self.context.preprocess_proto(child)?;

let child_handle = self.context.set_labeled_asset(
&format!("{:0>3}--{:0>3}", self.context.depth(), self.child_count),
meta.path.label().expect("child should have an asset label"),
LoadedAsset::new(child).with_dependencies(deps),
);

self.child_count += 1;
self.context.increment_index();

Ok(child_handle)
}

/// Add the child with the given path to the parent.
pub fn add_child_path(&mut self, child_path: ProtoPath) -> Result<Handle<T>, T::Error> {
pub fn add_child_path(&mut self, child_path: ProtoPath) -> Result<Handle<T>, L::Error> {
self.context
.child_paths_mut()
.push(child_path.asset_path().to_owned());

self.child_count += 1;
self.context.increment_index();

Ok(self.context.get_handle(child_path))
}

/// Access the current [`ProtoLoadContext`].
pub fn context(&self) -> &ProtoLoadContext<'ctx, 'load_ctx, T> {
pub fn context(&self) -> &ProtoLoadContext<'ctx, 'load_ctx, T, L> {
&self.context
}

/// Access the current [`ProtoLoadContext`] mutably.
pub fn context_mut(&mut self) -> &mut ProtoLoadContext<'ctx, 'load_ctx, T> {
pub fn context_mut(&mut self) -> &mut ProtoLoadContext<'ctx, 'load_ctx, T, L> {
&mut self.context
}
}

impl<'ctx, 'load_ctx, T: Prototypical> ProtoPathContext for ProtoChildBuilder<'ctx, 'load_ctx, T> {
impl<'ctx, 'load_ctx, T: Prototypical, L: Loader<T>> ProtoPathContext
for ProtoChildBuilder<'ctx, 'load_ctx, T, L>
{
fn base_path(&self) -> &Path {
self.context.base_path()
}
Expand Down
67 changes: 67 additions & 0 deletions bevy_proto_backend/src/load/asset_loader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::marker::PhantomData;
use std::sync::Arc;

use bevy::app::AppTypeRegistry;
use bevy::asset::{AssetLoader, AssetPath, BoxedFuture, LoadContext, LoadedAsset};
use bevy::prelude::{Handle, World};
use parking_lot::RwLock;

use crate::load::{Loader, ProtoLoadContext};
use crate::proto::{Config, Prototypical};
use crate::registration::{LoadQueue, ProtoRegistry};

pub(crate) struct ProtoAssetLoader<T: Prototypical, L: Loader<T>, C: Config<T>> {
registry: AppTypeRegistry,
proto_registry: Arc<RwLock<LoadQueue<T>>>,
loader: L,
_phantom: PhantomData<C>,
}

impl<T: Prototypical, L: Loader<T>, C: Config<T>> ProtoAssetLoader<T, L, C> {
pub fn new(loader: L, world: &mut World) -> Self {
world.init_resource::<AppTypeRegistry>();
world.init_resource::<ProtoRegistry<T, C>>();

Self {
registry: world.resource::<AppTypeRegistry>().clone(),
proto_registry: world.resource::<ProtoRegistry<T, C>>().load_queue().clone(),
loader,
_phantom: Default::default(),
}
}
}

impl<T: Prototypical, L: Loader<T>, C: Config<T>> AssetLoader for ProtoAssetLoader<T, L, C> {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, anyhow::Result<(), anyhow::Error>> {
Box::pin(async {
let registry = self.registry.read();
let mut ctx = ProtoLoadContext::<T, L>::new(&registry, &self.loader, load_context);

// 1. Deserialize the prototype
let prototype = L::deserialize(bytes, &mut ctx)?;
let (prototype, _, mut dependency_paths) = ctx.preprocess_proto(prototype)?;
dependency_paths.append(ctx.child_paths_mut());

// 2. Register
let asset_handle: Handle<T> =
load_context.get_handle(AssetPath::new_ref(load_context.path(), None));
self.proto_registry
.write()
.queue(prototype.id().clone(), &asset_handle);

// 3. Finish!
let asset = LoadedAsset::new(prototype).with_dependencies(dependency_paths);
load_context.set_default_asset(asset);

Ok(())
})
}

fn extensions(&self) -> &[&str] {
self.loader.extensions()
}
}
Loading

0 comments on commit b6c2072

Please sign in to comment.