bevy_defer/access/
async_asset.rs1use std::any::type_name;
2use std::sync::atomic::{AtomicI32, Ordering};
3use std::sync::Arc;
4
5use crate::access::AsyncWorld;
6use crate::executor::{with_world_mut, ASSET_SERVER};
7use crate::sync::oneshot::MaybeChannelOut;
8use crate::{AccessError, AccessResult};
9use bevy::asset::meta::Settings;
10use bevy::asset::{Asset, AssetId, AssetPath, AssetServer, Assets, Handle, LoadState};
11use bevy::ecs::world::World;
12use event_listener::Event;
13use futures::future::{ready, Either};
14
15#[derive(Debug, Default)]
16pub struct AssetBarrierInner {
17 pub count: AtomicI32,
18 pub notify: Event,
19}
20
21#[derive(Debug, Default)]
22pub struct AssetBarrierGuard(Arc<AssetBarrierInner>);
23
24impl Clone for AssetBarrierGuard {
25 fn clone(&self) -> Self {
26 self.0.count.fetch_add(1, Ordering::AcqRel);
27 Self(self.0.clone())
28 }
29}
30
31impl Drop for AssetBarrierGuard {
32 fn drop(&mut self) {
33 let prev = self.0.count.fetch_sub(1, Ordering::AcqRel);
34 if prev <= 1 {
35 self.0.notify.notify(usize::MAX);
36 }
37 }
38}
39
40#[derive(Debug, Default)]
42pub struct AssetSet(Arc<AssetBarrierInner>);
43
44impl AssetSet {
45 pub fn new(&self) -> AssetSet {
46 AssetSet::default()
47 }
48
49 pub fn load<A: Asset>(&self, path: impl Into<AssetPath<'static>>) -> Handle<A> {
51 if !ASSET_SERVER.is_set() {
52 panic!("AssetServer does not exist.")
53 }
54 self.0.count.fetch_add(1, Ordering::AcqRel);
55 ASSET_SERVER.with(|s| s.load_acquire::<A, _>(path, AssetBarrierGuard(self.0.clone())))
56 }
57
58 pub async fn wait(&self) {
60 loop {
61 if self.0.count.load(Ordering::Acquire) == 0 {
62 return;
63 }
64 self.0.notify.listen().await;
65 }
66 }
67}
68
69#[derive(Debug)]
71pub struct AsyncAsset<A: Asset>(pub(crate) Handle<A>);
72
73impl<A: Asset> Clone for AsyncAsset<A> {
74 fn clone(&self) -> Self {
75 Self(self.0.clone())
76 }
77}
78
79impl<A: Asset> From<Handle<A>> for AsyncAsset<A> {
80 fn from(value: Handle<A>) -> Self {
81 AsyncAsset(value)
82 }
83}
84
85impl<A: Asset> From<&AsyncAsset<A>> for AssetId<A> {
86 fn from(val: &AsyncAsset<A>) -> Self {
87 val.id()
88 }
89}
90
91impl AsyncWorld {
92 pub fn asset<A: Asset>(&self, handle: impl Into<AssetId<A>>) -> AsyncAsset<A> {
103 AsyncAsset(Handle::Weak(handle.into()))
104 }
105
106 pub fn load_asset<A: Asset>(
121 &self,
122 path: impl Into<AssetPath<'static>> + Send + 'static,
123 ) -> AsyncAsset<A> {
124 if !ASSET_SERVER.is_set() {
125 panic!("AssetServer does not exist.")
126 }
127 AsyncAsset(ASSET_SERVER.with(|s| s.load::<A>(path)))
128 }
129
130 pub fn load_asset_with_settings<A: Asset, S: Settings>(
133 &self,
134 path: impl Into<AssetPath<'static>> + Send + 'static,
135 f: impl Fn(&mut S) + Send + Sync + 'static,
136 ) -> AsyncAsset<A> {
137 if !ASSET_SERVER.is_set() {
138 panic!("AssetServer does not exist.")
139 }
140 AsyncAsset(ASSET_SERVER.with(|s| s.load_with_settings::<A, S>(path, f)))
141 }
142
143 pub fn add_asset<A: Asset + 'static>(&self, item: A) -> AccessResult<Handle<A>> {
145 with_world_mut(|w| {
146 Ok(w.get_resource_mut::<Assets<A>>()
147 .ok_or(AccessError::ResourceNotFound {
148 name: type_name::<Assets<A>>(),
149 })?
150 .add(item))
151 })
152 }
153}
154
155impl<A: Asset> AsyncAsset<A> {
156 pub fn id(&self) -> AssetId<A> {
158 self.0.id()
159 }
160
161 pub fn handle(&self) -> &Handle<A> {
163 &self.0
164 }
165
166 pub fn from_handle(handle: Handle<A>) -> Self {
168 AsyncAsset(handle)
169 }
170
171 pub fn into_handle(self) -> Handle<A> {
173 self.0
174 }
175
176 pub fn loaded(&self) -> MaybeChannelOut<bool> {
178 if !ASSET_SERVER.is_set() {
179 panic!("AssetServer does not exist.")
180 }
181 match ASSET_SERVER.with(|server| server.load_state(&self.0)) {
182 LoadState::Loaded => return Either::Right(ready(true)),
183 LoadState::Failed(..) => return Either::Right(ready(false)),
184 _ => (),
185 };
186 let handle = self.0.id();
187 AsyncWorld.watch_left(move |world: &mut World| {
188 match world.resource::<AssetServer>().load_state(handle) {
189 LoadState::Loaded => Some(true),
190 LoadState::Failed(..) => Some(false),
191 _ => None,
192 }
193 })
194 }
195}