bevy_asset/
event.rs

1use crate::{Asset, AssetId, AssetLoadError, AssetPath, UntypedAssetId};
2use bevy_ecs::event::Event;
3use bevy_reflect::Reflect;
4use core::fmt::Debug;
5
6/// An event emitted when a specific [`Asset`] fails to load.
7///
8/// For an untyped equivalent, see [`UntypedAssetLoadFailedEvent`].
9#[derive(Event, Clone, Debug)]
10pub struct AssetLoadFailedEvent<A: Asset> {
11    pub id: AssetId<A>,
12    /// The asset path that was attempted.
13    pub path: AssetPath<'static>,
14    /// Why the asset failed to load.
15    pub error: AssetLoadError,
16}
17
18impl<A: Asset> AssetLoadFailedEvent<A> {
19    /// Converts this to an "untyped" / "generic-less" asset error event that stores the type information.
20    pub fn untyped(&self) -> UntypedAssetLoadFailedEvent {
21        self.into()
22    }
23}
24
25/// An untyped version of [`AssetLoadFailedEvent`].
26#[derive(Event, Clone, Debug)]
27pub struct UntypedAssetLoadFailedEvent {
28    pub id: UntypedAssetId,
29    /// The asset path that was attempted.
30    pub path: AssetPath<'static>,
31    /// Why the asset failed to load.
32    pub error: AssetLoadError,
33}
34
35impl<A: Asset> From<&AssetLoadFailedEvent<A>> for UntypedAssetLoadFailedEvent {
36    fn from(value: &AssetLoadFailedEvent<A>) -> Self {
37        UntypedAssetLoadFailedEvent {
38            id: value.id.untyped(),
39            path: value.path.clone(),
40            error: value.error.clone(),
41        }
42    }
43}
44
45/// Events that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
46#[derive(Event, Reflect)]
47pub enum AssetEvent<A: Asset> {
48    /// Emitted whenever an [`Asset`] is added.
49    Added { id: AssetId<A> },
50    /// Emitted whenever an [`Asset`] value is modified.
51    Modified { id: AssetId<A> },
52    /// Emitted whenever an [`Asset`] is removed.
53    Removed { id: AssetId<A> },
54    /// Emitted when the last [`super::Handle::Strong`] of an [`Asset`] is dropped.
55    Unused { id: AssetId<A> },
56    /// Emitted whenever an [`Asset`] has been fully loaded (including its dependencies and all "recursive dependencies").
57    LoadedWithDependencies { id: AssetId<A> },
58}
59
60impl<A: Asset> AssetEvent<A> {
61    /// Returns `true` if this event is [`AssetEvent::LoadedWithDependencies`] and matches the given `id`.
62    pub fn is_loaded_with_dependencies(&self, asset_id: impl Into<AssetId<A>>) -> bool {
63        matches!(self, AssetEvent::LoadedWithDependencies { id } if *id == asset_id.into())
64    }
65
66    /// Returns `true` if this event is [`AssetEvent::Added`] and matches the given `id`.
67    pub fn is_added(&self, asset_id: impl Into<AssetId<A>>) -> bool {
68        matches!(self, AssetEvent::Added { id } if *id == asset_id.into())
69    }
70
71    /// Returns `true` if this event is [`AssetEvent::Modified`] and matches the given `id`.
72    pub fn is_modified(&self, asset_id: impl Into<AssetId<A>>) -> bool {
73        matches!(self, AssetEvent::Modified { id } if *id == asset_id.into())
74    }
75
76    /// Returns `true` if this event is [`AssetEvent::Removed`] and matches the given `id`.
77    pub fn is_removed(&self, asset_id: impl Into<AssetId<A>>) -> bool {
78        matches!(self, AssetEvent::Removed { id } if *id == asset_id.into())
79    }
80
81    /// Returns `true` if this event is [`AssetEvent::Unused`] and matches the given `id`.
82    pub fn is_unused(&self, asset_id: impl Into<AssetId<A>>) -> bool {
83        matches!(self, AssetEvent::Unused { id } if *id == asset_id.into())
84    }
85}
86
87impl<A: Asset> Clone for AssetEvent<A> {
88    fn clone(&self) -> Self {
89        *self
90    }
91}
92
93impl<A: Asset> Copy for AssetEvent<A> {}
94
95impl<A: Asset> Debug for AssetEvent<A> {
96    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97        match self {
98            Self::Added { id } => f.debug_struct("Added").field("id", id).finish(),
99            Self::Modified { id } => f.debug_struct("Modified").field("id", id).finish(),
100            Self::Removed { id } => f.debug_struct("Removed").field("id", id).finish(),
101            Self::Unused { id } => f.debug_struct("Unused").field("id", id).finish(),
102            Self::LoadedWithDependencies { id } => f
103                .debug_struct("LoadedWithDependencies")
104                .field("id", id)
105                .finish(),
106        }
107    }
108}
109
110impl<A: Asset> PartialEq for AssetEvent<A> {
111    fn eq(&self, other: &Self) -> bool {
112        match (self, other) {
113            (Self::Added { id: l_id }, Self::Added { id: r_id })
114            | (Self::Modified { id: l_id }, Self::Modified { id: r_id })
115            | (Self::Removed { id: l_id }, Self::Removed { id: r_id })
116            | (Self::Unused { id: l_id }, Self::Unused { id: r_id })
117            | (
118                Self::LoadedWithDependencies { id: l_id },
119                Self::LoadedWithDependencies { id: r_id },
120            ) => l_id == r_id,
121            _ => false,
122        }
123    }
124}
125
126impl<A: Asset> Eq for AssetEvent<A> {}