use crate::{Asset, AssetId, AssetLoadError, AssetPath, UntypedAssetId}; use bevy_ecs::event::Event; use std::fmt::Debug; /// An event emitted when a specific [`Asset`] fails to load. /// /// For an untyped equivalent, see [`UntypedAssetLoadFailedEvent`]. #[derive(Event, Clone, Debug)] pub struct AssetLoadFailedEvent { pub id: AssetId, /// The asset path that was attempted. pub path: AssetPath<'static>, /// Why the asset failed to load. pub error: AssetLoadError, } impl AssetLoadFailedEvent { /// Converts this to an "untyped" / "generic-less" asset error event that stores the type information. pub fn untyped(&self) -> UntypedAssetLoadFailedEvent { self.into() } } /// An untyped version of [`AssetLoadFailedEvent`]. #[derive(Event, Clone, Debug)] pub struct UntypedAssetLoadFailedEvent { pub id: UntypedAssetId, /// The asset path that was attempted. pub path: AssetPath<'static>, /// Why the asset failed to load. pub error: AssetLoadError, } impl From<&AssetLoadFailedEvent> for UntypedAssetLoadFailedEvent { fn from(value: &AssetLoadFailedEvent) -> Self { UntypedAssetLoadFailedEvent { id: value.id.untyped(), path: value.path.clone(), error: value.error.clone(), } } } /// Events that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events. #[derive(Event)] pub enum AssetEvent { /// Emitted whenever an [`Asset`] is added. Added { id: AssetId }, /// Emitted whenever an [`Asset`] value is modified. Modified { id: AssetId }, /// Emitted whenever an [`Asset`] is removed. Removed { id: AssetId }, /// Emitted when the last [`super::Handle::Strong`] of an [`Asset`] is dropped. Unused { id: AssetId }, /// Emitted whenever an [`Asset`] has been fully loaded (including its dependencies and all "recursive dependencies"). LoadedWithDependencies { id: AssetId }, } impl AssetEvent { /// Returns `true` if this event is [`AssetEvent::LoadedWithDependencies`] and matches the given `id`. pub fn is_loaded_with_dependencies(&self, asset_id: impl Into>) -> bool { matches!(self, AssetEvent::LoadedWithDependencies { id } if *id == asset_id.into()) } /// Returns `true` if this event is [`AssetEvent::Added`] and matches the given `id`. pub fn is_added(&self, asset_id: impl Into>) -> bool { matches!(self, AssetEvent::Added { id } if *id == asset_id.into()) } /// Returns `true` if this event is [`AssetEvent::Modified`] and matches the given `id`. pub fn is_modified(&self, asset_id: impl Into>) -> bool { matches!(self, AssetEvent::Modified { id } if *id == asset_id.into()) } /// Returns `true` if this event is [`AssetEvent::Removed`] and matches the given `id`. pub fn is_removed(&self, asset_id: impl Into>) -> bool { matches!(self, AssetEvent::Removed { id } if *id == asset_id.into()) } /// Returns `true` if this event is [`AssetEvent::Unused`] and matches the given `id`. pub fn is_unused(&self, asset_id: impl Into>) -> bool { matches!(self, AssetEvent::Unused { id } if *id == asset_id.into()) } } impl Clone for AssetEvent { fn clone(&self) -> Self { *self } } impl Copy for AssetEvent {} impl Debug for AssetEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Added { id } => f.debug_struct("Added").field("id", id).finish(), Self::Modified { id } => f.debug_struct("Modified").field("id", id).finish(), Self::Removed { id } => f.debug_struct("Removed").field("id", id).finish(), Self::Unused { id } => f.debug_struct("Unused").field("id", id).finish(), Self::LoadedWithDependencies { id } => f .debug_struct("LoadedWithDependencies") .field("id", id) .finish(), } } } impl PartialEq for AssetEvent { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Added { id: l_id }, Self::Added { id: r_id }) | (Self::Modified { id: l_id }, Self::Modified { id: r_id }) | (Self::Removed { id: l_id }, Self::Removed { id: r_id }) | (Self::Unused { id: l_id }, Self::Unused { id: r_id }) | ( Self::LoadedWithDependencies { id: l_id }, Self::LoadedWithDependencies { id: r_id }, ) => l_id == r_id, _ => false, } } } impl Eq for AssetEvent {}