bevy_asset_loader/loading_state/
config.rs1use crate::asset_collection::AssetCollection;
2use crate::dynamic_asset::{DynamicAssetCollection, DynamicAssetCollections};
3use crate::loading_state::dynamic_asset_systems::{
4 check_dynamic_asset_collections, load_dynamic_asset_collections,
5};
6use crate::loading_state::systems::{
7 check_loading_collection, finally_init_resource, start_loading_collection,
8};
9use crate::loading_state::{
10 InternalLoadingState, InternalLoadingStateSet, LoadingStateSchedule,
11 OnEnterInternalLoadingState,
12};
13use bevy::app::App;
14use bevy::asset::Asset;
15use bevy::ecs::schedule::ScheduleConfigs;
16use bevy::platform::collections::HashMap;
17use bevy::prelude::{BevyError, FromWorld, IntoScheduleConfigs, Resource, default};
18use bevy::state::state::FreelyMutableState;
19use std::any::TypeId;
20
21pub trait ConfigureLoadingState {
23 #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
30 fn load_collection<A: AssetCollection>(self) -> Self;
31
32 #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
37 fn finally_init_resource<R: Resource + FromWorld>(self) -> Self;
38
39 #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
43 fn register_dynamic_asset_collection<C: DynamicAssetCollection + Asset>(self) -> Self;
44
45 #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
50 fn with_dynamic_assets_file<C: DynamicAssetCollection + Asset>(self, file: &str) -> Self;
51
52 #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
57 #[deprecated(
58 since = "0.22.1",
59 note = "Method has been renamed to `finally_init_resource`"
60 )]
61 fn init_resource<R: Resource + FromWorld>(self) -> Self;
62}
63
64type SchedulConfig = ScheduleConfigs<
65 Box<(dyn bevy::prelude::System<In = (), Out = Result<(), BevyError>> + 'static)>,
66>;
67
68pub struct LoadingStateConfig<S: FreelyMutableState> {
105 state: S,
106
107 on_enter_loading_assets: Vec<SchedulConfig>,
108 on_enter_loading_dynamic_asset_collections: Vec<SchedulConfig>,
109 on_update: Vec<SchedulConfig>,
110 on_enter_finalize: Vec<SchedulConfig>,
111
112 dynamic_assets: HashMap<TypeId, Vec<String>>,
113}
114
115impl<S: FreelyMutableState> LoadingStateConfig<S> {
116 pub fn new(state: S) -> Self {
118 Self {
119 state,
120 on_enter_loading_assets: vec![],
121 on_enter_loading_dynamic_asset_collections: vec![],
122 on_update: vec![],
123 on_enter_finalize: vec![],
124 dynamic_assets: default(),
125 }
126 }
127
128 pub(crate) fn with_dynamic_assets_type_id(&mut self, file: &str, type_id: TypeId) {
129 let mut dynamic_files = self.dynamic_assets.remove(&type_id).unwrap_or_default();
130 dynamic_files.push(file.to_owned());
131 self.dynamic_assets.insert(type_id, dynamic_files);
132 }
133
134 pub(crate) fn build(mut self, app: &mut App) {
135 for config in self.on_enter_loading_assets {
136 app.add_systems(
137 OnEnterInternalLoadingState(
138 self.state.clone(),
139 InternalLoadingState::LoadingAssets,
140 ),
141 config,
142 );
143 }
144 for config in self.on_update {
145 app.add_systems(LoadingStateSchedule(self.state.clone()), config);
146 }
147 for config in self.on_enter_finalize {
148 app.add_systems(
149 OnEnterInternalLoadingState(self.state.clone(), InternalLoadingState::Finalize),
150 config,
151 );
152 }
153 for config in self.on_enter_loading_dynamic_asset_collections.drain(..) {
154 app.add_systems(
155 OnEnterInternalLoadingState(
156 self.state.clone(),
157 InternalLoadingState::LoadingDynamicAssetCollections,
158 ),
159 config,
160 );
161 }
162 let mut dynamic_assets = app
163 .world_mut()
164 .get_resource_mut::<DynamicAssetCollections<S>>()
165 .unwrap_or_else(|| {
166 panic!("Failed to get the DynamicAssetCollections resource for the loading state. Are you trying to configure a loading state before it was added to the bevy App?")
167 });
168 for (id, files) in self.dynamic_assets.drain() {
169 dynamic_assets.register_files_by_type_id(self.state.clone(), files, id);
170 }
171 }
172}
173
174impl<S: FreelyMutableState> ConfigureLoadingState for LoadingStateConfig<S> {
175 fn load_collection<A: AssetCollection>(mut self) -> Self {
176 self.on_enter_loading_assets
177 .push(start_loading_collection::<S, A>.into_configs());
178 self.on_update.push(
179 check_loading_collection::<S, A>
180 .in_set(InternalLoadingStateSet::CheckAssets)
181 .into_configs(),
182 );
183
184 self
185 }
186
187 fn finally_init_resource<R: Resource + FromWorld>(mut self) -> Self {
188 self.on_enter_finalize
189 .push(finally_init_resource::<R>.into_configs());
190
191 self
192 }
193
194 fn register_dynamic_asset_collection<C: DynamicAssetCollection + Asset>(mut self) -> Self {
195 self.on_enter_loading_dynamic_asset_collections
196 .push(load_dynamic_asset_collections::<S, C>.into_configs());
197 self.on_update.push(
198 check_dynamic_asset_collections::<S, C>
199 .in_set(InternalLoadingStateSet::CheckDynamicAssetCollections),
200 );
201
202 self
203 }
204
205 fn with_dynamic_assets_file<C: DynamicAssetCollection + Asset>(mut self, file: &str) -> Self {
206 self.with_dynamic_assets_type_id(file, TypeId::of::<C>());
207
208 self
209 }
210
211 fn init_resource<R: Resource + FromWorld>(self) -> Self {
212 self.finally_init_resource::<R>()
213 }
214}