Skip to content

Commit

Permalink
Improve reload detection
Browse files Browse the repository at this point in the history
  • Loading branch information
MrGVSV committed Apr 29, 2023
1 parent 50843e0 commit e9122c2
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 108 deletions.
19 changes: 13 additions & 6 deletions bevy_proto_backend/src/proto/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,30 @@ pub trait Config<T: Prototypical>: Resource + FromWorld {

/// Callback method that's triggered when a [prototype] is registered.
///
/// Prototypes are registered when they are either loaded or modified.
/// In the latter case, they will be unregistered and immediately re-registered.
/// Prototypes are registered when they are first loaded.
///
/// This method will be given the registered prototype and its corresponding _strong_ [`Handle`].
///
/// [prototype]: Prototypical
fn on_register_prototype(&mut self, prototype: &T, handle: Handle<T>) {}

/// Callback method that's triggered when a [prototype] is reloaded.
///
/// Prototypes are reloaded whenever they or one of their dependencies are modified.
///
/// This method will be given the reloaded prototype and its corresponding _strong_ [`Handle`].
///
/// [prototype]: Prototypical
fn on_reload_prototype(&mut self, prototype: &T, handle: Handle<T>) {}

/// Callback method that's triggered when a [prototype] is unregistered.
///
/// Prototypes are unregistered when they are either removed or modified.
/// In the latter case, they will be unregistered and immediately re-registered.
/// Prototypes are unregistered when they are unloaded.
///
/// This method will be given the unregistered prototype and its corresponding _strong_ [`Handle`].
/// This method will be given the unregistered prototype's ID and its corresponding _strong_ [`Handle`].
///
/// [prototype]: Prototypical
fn on_unregister_prototype(&mut self, prototype: &T, handle: Handle<T>) {}
fn on_unregister_prototype(&mut self, id: &T::Id, handle: Handle<T>) {}

/// Callback method that's triggered _before_ a [prototype] is applied to an entity.
///
Expand Down
3 changes: 3 additions & 0 deletions bevy_proto_backend/src/proto/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ pub enum ProtoError {
/// [prototype]: crate::proto::Prototypical
#[error("the prototype with handle {0:?} either doesn't exist or isn't fully loaded")]
DoesNotExist(HandleUntyped),
/// Indicates that a prototype with the given handle is not registered.
#[error("the prototype with handle {0:?} is not registered")]
NotRegistered(HandleUntyped),
/// Indicates that a prototype tried to be registered with an existing ID.
#[error("attempted to register prototype with ID {id:?} (`{path:?}`), but one already exists with this ID (`{existing:?}`)")]
AlreadyExists {
Expand Down
60 changes: 53 additions & 7 deletions bevy_proto_backend/src/proto/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bevy::asset::Handle;
///
/// [prototype]: Prototypical
/// [`AssetEvent`]: bevy::asset::AssetEvent
#[derive(Debug, PartialEq)]
pub enum ProtoAssetEvent<T: Prototypical> {
/// This event is fired when a prototype has been successfully created,
/// registered, and cached.
Expand All @@ -18,8 +19,10 @@ pub enum ProtoAssetEvent<T: Prototypical> {
/// A weak handle to the prototype asset.
handle: Handle<T>,
},
/// This event is fired when a prototype has been modified, such as when
/// a change is made to the file while hot-reloading is enabled.
/// This event is fired when a prototype has been modified.
///
/// This includes when a prototype is directly modified or when one its
/// dependencies is modified.
Modified {
/// The ID of the modified prototype.
id: T::Id,
Expand All @@ -28,12 +31,55 @@ pub enum ProtoAssetEvent<T: Prototypical> {
},
/// This event is fired when a prototype has been fully unloaded.
Removed {
/// The ID of the removed prototype.
///
/// This will almost always be `Some` unless a duplicate removal happens
/// to occur at the same time, in which case it may be `None`.
id: Option<T::Id>,
/// The ID of the created prototype.
id: T::Id,
/// A weak handle to the prototype asset.
handle: Handle<T>,
},
}

impl<T: Prototypical> ProtoAssetEvent<T> {
/// Returns the ID of the prototype.
pub fn id(&self) -> &T::Id {
match self {
ProtoAssetEvent::Created { id, .. } => id,
ProtoAssetEvent::Modified { id, .. } => id,
ProtoAssetEvent::Removed { id, .. } => id,
}
}

/// Returns a weak handle to the prototype asset.
pub fn handle(&self) -> &Handle<T> {
match self {
ProtoAssetEvent::Created { handle, .. } => handle,
ProtoAssetEvent::Modified { handle, .. } => handle,
ProtoAssetEvent::Removed { handle, .. } => handle,
}
}

/// Returns true if the prototype with the given ID was created.
pub fn is_created<I: for<'a> PartialEq<&'a T::Id>>(&self, id: I) -> bool {
match self {
ProtoAssetEvent::Created { id: created_id, .. } => id == created_id,
_ => false,
}
}

/// Returns true if the prototype with the given ID was modified.
pub fn is_modified<I: for<'a> PartialEq<&'a T::Id>>(&self, id: I) -> bool {
match self {
ProtoAssetEvent::Modified {
id: modified_id, ..
} => id == modified_id,
_ => false,
}
}

/// Returns true if the prototype with the given ID was removed.
pub fn is_removed<I: for<'a> PartialEq<&'a T::Id>>(&self, id: I) -> bool {
match self {
ProtoAssetEvent::Removed { id: removed_id, .. } => id == removed_id,
_ => false,
}
}
}
22 changes: 12 additions & 10 deletions bevy_proto_backend/src/registration/manager.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use bevy::asset::{Assets, HandleId};
use bevy::asset::Handle;
use bevy::ecs::system::SystemParam;
use bevy::prelude::{Res, ResMut};
use bevy::prelude::ResMut;

use crate::proto::{ProtoError, Prototypical};
use crate::registration::params::RegistryParams;
use crate::registration::ProtoRegistry;

/// Manager [`SystemParam`] for [prototypes].
Expand All @@ -13,18 +14,19 @@ use crate::registration::ProtoRegistry;
#[derive(SystemParam)]
pub(crate) struct ProtoManager<'w, T: Prototypical> {
registry: ResMut<'w, ProtoRegistry<T>>,
prototypes: Res<'w, Assets<T>>,
config: ResMut<'w, <T as Prototypical>::Config>,
registry_params: RegistryParams<'w, T>,
}

impl<'w, T: Prototypical> ProtoManager<'w, T> {
pub fn register<H: Into<HandleId>>(&mut self, handle: H) -> Result<&T, ProtoError> {
self.registry
.register(handle, &self.prototypes, &mut self.config)
pub fn register(&mut self, handle: &Handle<T>) -> Result<&'w T, ProtoError> {
self.registry.register(handle, &mut self.registry_params)
}

pub fn unregister<H: Into<HandleId>>(&mut self, handle: H) -> Option<T::Id> {
self.registry
.unregister(handle, &self.prototypes, &mut self.config)
pub fn reload(&mut self, handle: &Handle<T>) -> Result<&'w T, ProtoError> {
self.registry.reload(handle, &mut self.registry_params)
}

pub fn unregister(&mut self, handle: &Handle<T>) -> Option<T::Id> {
self.registry.unregister(handle, &mut self.registry_params)
}
}
1 change: 1 addition & 0 deletions bevy_proto_backend/src/registration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ pub(crate) use registry::*;
pub(crate) use systems::*;

mod manager;
mod params;
mod registry;
mod systems;
39 changes: 39 additions & 0 deletions bevy_proto_backend/src/registration/params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::proto::{ProtoAssetEvent, ProtoError, Prototypical};
use bevy::asset::{Assets, Handle, HandleId};
use bevy::ecs::system::SystemParam;
use bevy::prelude::{EventWriter, Res, ResMut};

#[derive(SystemParam)]
pub(super) struct RegistryParams<'w, T: Prototypical> {
prototypes: Res<'w, Assets<T>>,
config: ResMut<'w, <T as Prototypical>::Config>,
proto_events: EventWriter<'w, ProtoAssetEvent<T>>,
}

impl<'w, T: Prototypical> RegistryParams<'w, T> {
pub fn prototypes(&self) -> &'w Assets<T> {
Res::clone(&self.prototypes).into_inner()
}

pub fn config(&self) -> &T::Config {
&self.config
}

pub fn config_mut(&mut self) -> &mut T::Config {
&mut self.config
}

pub fn get_prototype(&self, handle: &Handle<T>) -> Result<&'w T, ProtoError> {
self.prototypes()
.get(handle)
.ok_or_else(|| ProtoError::DoesNotExist(handle.clone_weak_untyped()))
}

pub fn get_strong_handle<H: Into<HandleId>>(&self, handle: H) -> Handle<T> {
self.prototypes().get_handle(handle)
}

pub fn send_event(&mut self, event: ProtoAssetEvent<T>) {
self.proto_events.send(event);
}
}
Loading

0 comments on commit e9122c2

Please sign in to comment.