Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PrototypesMut::load_folder #36

Merged
merged 4 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions bevy_proto_backend/src/proto/prototypes.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
use std::borrow::{Borrow, Cow};
use std::borrow::Borrow;

use bevy::asset::{Handle, HandleId, LoadState};
use bevy::asset::{AssetServerError, Handle, HandleId, HandleUntyped, LoadState};
use bevy::ecs::system::SystemParam;
use bevy::prelude::{AssetServer, Res, ResMut};
use std::hash::Hash;
use std::path::{Path, PathBuf};
use thiserror::Error;

use crate::proto::{ProtoStorage, Prototypical};
use crate::registration::ProtoRegistry;

#[derive(Debug, Error)]
pub enum ProtoLoadError {
/// Indicates that the [`AssetServer`] encountered an error.
#[error(transparent)]
AssetServerError(#[from] AssetServerError),
}

/// A helper [`SystemParam`] for managing [prototypes].
///
/// For the mutable version, see [`PrototypesMut`].
Expand Down Expand Up @@ -41,18 +50,44 @@ impl<'w, T: Prototypical> PrototypesMut<'w, T> {
/// To later remove this handle, call [`PrototypesMut::remove`] with the same path.
///
/// To load without automatically storing the handle, try using [`AssetServer::load`].
pub fn load<P: Into<Cow<'static, str>>>(&mut self, path: P) -> Handle<T> {
pub fn load<P: Into<PathBuf>>(&mut self, path: P) -> Handle<T> {
let path = path.into();
let handle = self.asset_server.load(path.as_ref());
let handle = self.asset_server.load(path.as_path());
self.storage.insert(path, handle.clone());
handle
}

/// Load all the prototypes in the given directory.
///
/// This will also store strong handles to the prototypes in order to keep them loaded.
///
/// To load without automatically storing the handles, try using [`AssetServer::load_folder`].
pub fn load_folder<P: Into<PathBuf>>(
&mut self,
path: P,
) -> Result<Vec<HandleUntyped>, ProtoLoadError> {
let path = path.into();
let handles: Vec<_> = self.asset_server.load_folder(&path)?;

for handle in &handles {
let path = self
.asset_server
.get_handle_path(handle)
.expect("handles loaded by path should return a path")
.path()
.to_owned();

self.storage.insert(path, handle.clone().typed::<T>());
}

Ok(handles)
}

/// Remove the stored handle for the given prototype path.
///
/// This allows the asset to be unloaded if the handle is dropped and no other
/// strong handles exist.
pub fn remove(&mut self, path: &str) -> Option<Handle<T>> {
pub fn remove<P: AsRef<Path>>(&mut self, path: P) -> Option<Handle<T>> {
self.storage.remove(path)
}

Expand Down Expand Up @@ -123,14 +158,14 @@ macro_rules! impl_prototypes {
}

/// Returns true if a prototype with the given path is currently stored.
pub fn contains(&self, path: &str) -> bool {
pub fn contains<P: AsRef<Path>>(&self, path: P) -> bool {
self.storage.contains(path)
}

/// Get a reference to the strong handle for the prototype at the given path.
///
/// Returns `None` if no matching prototype is currently stored.
pub fn get(&self, path: &str) -> Option<&Handle<T>> {
pub fn get<P: AsRef<Path>>(&self, path: P) -> Option<&Handle<T>> {
self.storage.get(path)
}

Expand Down
22 changes: 9 additions & 13 deletions bevy_proto_backend/src/proto/storage.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::path::{Path, PathBuf};

use bevy::asset::Handle;
use bevy::prelude::Resource;
Expand All @@ -11,20 +11,20 @@ use crate::proto::Prototypical;
/// [prototype]: Prototypical
#[derive(Resource)]
pub(crate) struct ProtoStorage<T: Prototypical> {
path_to_handle: HashMap<Cow<'static, str>, Handle<T>>,
path_to_handle: HashMap<PathBuf, Handle<T>>,
}

impl<T: Prototypical> ProtoStorage<T> {
/// Returns true if a prototype with the given path is currently stored in this resource.
pub fn contains(&self, path: &str) -> bool {
self.path_to_handle.contains_key(path)
pub fn contains<P: AsRef<Path>>(&self, path: P) -> bool {
self.path_to_handle.contains_key(path.as_ref())
}

/// Get a reference to the strong handle for the prototype at the given path.
///
/// Returns `None` if no matching prototype is currently stored in this resource.
pub fn get(&self, path: &str) -> Option<&Handle<T>> {
self.path_to_handle.get(path)
pub fn get<P: AsRef<Path>>(&self, path: P) -> Option<&Handle<T>> {
self.path_to_handle.get(path.as_ref())
}

/// Insert a prototype handle into this resource for the given path.
Expand All @@ -34,18 +34,14 @@ impl<T: Prototypical> ProtoStorage<T> {
/// # Panics
///
/// Panics if the given handle is weak.
pub fn insert<P: Into<Cow<'static, str>>>(
&mut self,
path: P,
handle: Handle<T>,
) -> Option<Handle<T>> {
pub fn insert<P: Into<PathBuf>>(&mut self, path: P, handle: Handle<T>) -> Option<Handle<T>> {
debug_assert!(handle.is_strong(), "attempted to store weak handle");
self.path_to_handle.insert(path.into(), handle)
}

/// Remove the handle with the given path.
pub fn remove(&mut self, path: &str) -> Option<Handle<T>> {
self.path_to_handle.remove(path)
pub fn remove<P: AsRef<Path>>(&mut self, path: P) -> Option<Handle<T>> {
self.path_to_handle.remove(path.as_ref())
}

/// Remove all handles.
Expand Down