Skip to content

Commit 5615837

Browse files
committed
refactor asset systems, make use of internal script asset events
1 parent bd77029 commit 5615837

File tree

3 files changed

+95
-85
lines changed

3 files changed

+95
-85
lines changed

crates/bevy_mod_scripting_core/src/asset.rs

Lines changed: 83 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use bevy::{
88
app::{App, PreUpdate},
99
asset::{Asset, AssetEvent, AssetId, AssetLoader, Assets},
1010
ecs::system::Resource,
11-
log::{error, info, trace},
12-
prelude::{Commands, EventReader, IntoSystemConfigs, IntoSystemSetConfigs, Res, ResMut},
11+
log::{debug, error, info, trace},
12+
prelude::{
13+
Commands, Event, EventReader, EventWriter, IntoSystemConfigs, IntoSystemSetConfigs, Res,
14+
ResMut,
15+
},
1316
reflect::TypePath,
1417
utils::HashMap,
1518
};
@@ -49,6 +52,13 @@ pub struct ScriptAsset {
4952
pub asset_path: PathBuf,
5053
}
5154

55+
#[derive(Event, Debug, Clone)]
56+
pub(crate) enum ScriptAssetEvent {
57+
Added(ScriptMetadata),
58+
Removed(ScriptMetadata),
59+
Modified(ScriptMetadata),
60+
}
61+
5262
#[derive(Default)]
5363
pub struct ScriptAssetLoader {
5464
/// The file extensions this loader should handle
@@ -140,6 +150,7 @@ pub struct ScriptMetadataStore {
140150

141151
#[derive(Debug, Clone, PartialEq, Eq)]
142152
pub struct ScriptMetadata {
153+
pub asset_id: AssetId<ScriptAsset>,
143154
pub script_id: ScriptId,
144155
pub language: Language,
145156
}
@@ -157,78 +168,94 @@ impl ScriptMetadataStore {
157168
pub fn remove(&mut self, id: AssetId<ScriptAsset>) -> Option<ScriptMetadata> {
158169
self.map.remove(&id)
159170
}
171+
172+
pub fn contains(&self, id: AssetId<ScriptAsset>) -> bool {
173+
self.map.contains_key(&id)
174+
}
160175
}
161176

162-
/// Listens to `AssetEvent<ScriptAsset>::Added` events and populates the script metadata store
163-
pub fn insert_script_metadata(
177+
/// Converts incoming asset events, into internal script asset events, also loads and inserts metadata for newly added scripts
178+
pub(crate) fn dispatch_script_asset_events(
164179
mut events: EventReader<AssetEvent<ScriptAsset>>,
165-
script_assets: Res<Assets<ScriptAsset>>,
166-
mut asset_path_map: ResMut<ScriptMetadataStore>,
180+
mut script_asset_events: EventWriter<ScriptAssetEvent>,
181+
assets: Res<Assets<ScriptAsset>>,
182+
mut metadata_store: ResMut<ScriptMetadataStore>,
167183
settings: Res<ScriptAssetSettings>,
168184
) {
169185
for event in events.read() {
170-
if let AssetEvent::LoadedWithDependencies { id } = event {
171-
let asset = script_assets.get(*id);
172-
if let Some(asset) = asset {
173-
let path = &asset.asset_path;
174-
let converter = settings.script_id_mapper.map;
175-
let script_id = converter(path);
176-
177-
let language = settings.select_script_language(path);
178-
let metadata = ScriptMetadata {
179-
script_id,
180-
language,
181-
};
182-
info!("Populating script metadata for script: {:?}:", metadata);
183-
asset_path_map.insert(*id, metadata);
184-
} else {
185-
error!("A script was added but it's asset was not found, failed to compute metadata. This script will not be loaded. {}", id);
186+
match event {
187+
AssetEvent::LoadedWithDependencies { id } | AssetEvent::Added { id } => {
188+
// these can occur multiple times, we only send one added event though
189+
if !metadata_store.contains(*id) {
190+
let asset = assets.get(*id);
191+
if let Some(asset) = asset {
192+
let path = &asset.asset_path;
193+
let converter = settings.script_id_mapper.map;
194+
let script_id = converter(path);
195+
196+
let language = settings.select_script_language(path);
197+
let metadata = ScriptMetadata {
198+
asset_id: *id,
199+
script_id,
200+
language,
201+
};
202+
debug!("Script loaded, populating metadata: {:?}:", metadata);
203+
script_asset_events.send(ScriptAssetEvent::Added(metadata.clone()));
204+
metadata_store.insert(*id, metadata);
205+
} else {
206+
error!("A script was added but it's asset was not found, failed to compute metadata. This script will not be loaded. {}", id);
207+
}
208+
}
209+
}
210+
AssetEvent::Removed { id } => {
211+
if let Some(metadata) = metadata_store.get(*id) {
212+
debug!("Script removed: {:?}", metadata);
213+
script_asset_events.send(ScriptAssetEvent::Removed(metadata.clone()));
214+
} else {
215+
error!("Script metadata not found for removed script asset: {}. Cannot properly clean up script", id);
216+
}
186217
}
218+
AssetEvent::Modified { id } => {
219+
if let Some(metadata) = metadata_store.get(*id) {
220+
debug!("Script modified: {:?}", metadata);
221+
script_asset_events.send(ScriptAssetEvent::Modified(metadata.clone()));
222+
} else {
223+
error!("Script metadata not found for modified script asset: {}. Cannot properly update script", id);
224+
}
225+
}
226+
_ => {}
187227
}
188228
}
189229
}
190230

191-
/// Listens to [`AssetEvent<ScriptAsset>::Removed`] events and removes the corresponding script metadata
192-
pub fn remove_script_metadata(
193-
mut events: EventReader<AssetEvent<ScriptAsset>>,
231+
/// Listens to [`ScriptAssetEvent::Removed`] events and removes the corresponding script metadata
232+
pub(crate) fn remove_script_metadata(
233+
mut events: EventReader<ScriptAssetEvent>,
194234
mut asset_path_map: ResMut<ScriptMetadataStore>,
195235
) {
196236
for event in events.read() {
197-
if let AssetEvent::Removed { id } = event {
198-
let previous = asset_path_map.remove(*id);
237+
if let ScriptAssetEvent::Removed(metadata) = event {
238+
let previous = asset_path_map.remove(metadata.asset_id);
199239
if let Some(previous) = previous {
200-
info!("Removed script metadata for removed script: {:?}", previous);
240+
debug!("Removed script metadata: {:?}", previous);
201241
}
202242
}
203243
}
204244
}
205245

206-
/// Listens to [`AssetEvent<ScriptAsset>`] events and dispatches [`CreateOrUpdateScript`] and [`DeleteScript`] commands accordingly.
246+
/// Listens to [`ScriptAssetEvent`] events and dispatches [`CreateOrUpdateScript`] and [`DeleteScript`] commands accordingly.
207247
///
208248
/// Allows for hot-reloading of scripts.
209-
pub fn sync_script_data<P: IntoScriptPluginParams>(
210-
mut events: EventReader<AssetEvent<ScriptAsset>>,
249+
pub(crate) fn sync_script_data<P: IntoScriptPluginParams>(
250+
mut events: EventReader<ScriptAssetEvent>,
211251
script_assets: Res<Assets<ScriptAsset>>,
212-
script_metadata: Res<ScriptMetadataStore>,
213252
mut commands: Commands,
214253
) {
215254
for event in events.read() {
216255
trace!("{}: Received script asset event: {:?}", P::LANGUAGE, event);
217256
match event {
218257
// emitted when a new script asset is loaded for the first time
219-
AssetEvent::LoadedWithDependencies { id } | AssetEvent::Modified { id } => {
220-
let metadata = match script_metadata.get(*id) {
221-
Some(m) => m,
222-
None => {
223-
error!(
224-
"{}: Script metadata not found for script asset with id: {}. Cannot load script.",
225-
P::LANGUAGE,
226-
id
227-
);
228-
continue;
229-
}
230-
};
231-
258+
ScriptAssetEvent::Added(metadata) | ScriptAssetEvent::Modified(metadata) => {
232259
if metadata.language != P::LANGUAGE {
233260
trace!(
234261
"{}: Script asset with id: {} is for a different langauge than this sync system. Skipping.",
@@ -238,43 +265,20 @@ pub fn sync_script_data<P: IntoScriptPluginParams>(
238265
continue;
239266
}
240267

241-
info!(
242-
"{}: Dispatching Creation/Modification command for script: {:?}. Asset Id: {}",
243-
P::LANGUAGE,
244-
metadata,
245-
id
246-
);
268+
info!("{}: Loading Script: {:?}", P::LANGUAGE, metadata.script_id,);
247269

248-
if let Some(asset) = script_assets.get(*id) {
270+
if let Some(asset) = script_assets.get(metadata.asset_id) {
249271
commands.queue(CreateOrUpdateScript::<P>::new(
250272
metadata.script_id.clone(),
251273
asset.content.clone(),
252274
Some(script_assets.reserve_handle().clone_weak()),
253275
));
254276
}
255277
}
256-
AssetEvent::Removed { id } => {
257-
let metadata = match script_metadata.get(*id) {
258-
Some(m) => m,
259-
None => {
260-
error!(
261-
"{}: Script metadata not found for script asset with id: {}. Cannot delete script.",
262-
P::LANGUAGE,
263-
id
264-
);
265-
return;
266-
}
267-
};
268-
269-
info!(
270-
"{}: Dispatching Deletion command for script: {:?}. Asset Id: {}",
271-
P::LANGUAGE,
272-
metadata,
273-
id
274-
);
278+
ScriptAssetEvent::Removed(metadata) => {
279+
info!("{}: Deleting Script: {:?}", P::LANGUAGE, metadata.script_id,);
275280
commands.queue(DeleteScript::<P>::new(metadata.script_id.clone()));
276281
}
277-
_ => return,
278282
};
279283
}
280284
}
@@ -286,21 +290,22 @@ pub(crate) fn configure_asset_systems(app: &mut App) -> &mut App {
286290
app.add_systems(
287291
PreUpdate,
288292
(
289-
insert_script_metadata.in_set(ScriptingSystemSet::ScriptMetadataInsertion),
293+
dispatch_script_asset_events.in_set(ScriptingSystemSet::ScriptAssetDispatch),
290294
remove_script_metadata.in_set(ScriptingSystemSet::ScriptMetadataRemoval),
291295
),
292296
)
293297
.configure_sets(
294298
PreUpdate,
295299
(
296-
ScriptingSystemSet::ScriptMetadataInsertion.after(bevy::asset::TrackAssets),
300+
ScriptingSystemSet::ScriptAssetDispatch.after(bevy::asset::TrackAssets),
297301
ScriptingSystemSet::ScriptCommandDispatch
298-
.after(ScriptingSystemSet::ScriptMetadataInsertion)
302+
.after(ScriptingSystemSet::ScriptAssetDispatch)
299303
.before(ScriptingSystemSet::ScriptMetadataRemoval),
300304
),
301305
)
302306
.init_resource::<ScriptMetadataStore>()
303-
.init_resource::<ScriptAssetSettings>();
307+
.init_resource::<ScriptAssetSettings>()
308+
.add_event::<ScriptAssetEvent>();
304309

305310
app
306311
}
@@ -455,6 +460,7 @@ mod tests {
455460
let mut store = ScriptMetadataStore::default();
456461
let id = AssetId::invalid();
457462
let meta = ScriptMetadata {
463+
asset_id: AssetId::invalid(),
458464
script_id: "test".into(),
459465
language: Language::Lua,
460466
};
@@ -544,7 +550,7 @@ mod tests {
544550
}
545551

546552
#[test]
547-
fn test_asset_metadata_insert_remove_systems() {
553+
fn test_asset_metadata_systems() {
548554
// test metadata flow
549555
let mut app = init_loader_test(ScriptAssetLoader {
550556
extensions: &[],

crates/bevy_mod_scripting_core/src/commands.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
144144
}
145145
}
146146

147+
#[inline(always)]
147148
fn reload_context(
148149
&self,
149150
world: &mut bevy::prelude::World,
@@ -188,7 +189,7 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
188189
Some(previous_context_id) => {
189190
if let Some(previous_context) = contexts.get_mut(previous_context_id) {
190191
let log_context = format!("{}: Reloading script: {}.", P::LANGUAGE, self.id);
191-
bevy::log::info!("{}", log_context);
192+
bevy::log::debug!("{}", log_context);
192193
if !self.reload_context(
193194
world,
194195
settings,
@@ -225,7 +226,7 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
225226
self.run_on_load_callback(settings, runtime, runner, world, existing_context);
226227
} else {
227228
// load new context
228-
bevy::log::info!("{}", log_context);
229+
bevy::log::debug!("{}", log_context);
229230
let ctxt = (builder.load)(
230231
&self.id,
231232
&self.content,

crates/bevy_mod_scripting_core/src/lib.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ pub mod script;
3434
#[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)]
3535
/// Labels for various BMS systems
3636
pub enum ScriptingSystemSet {
37-
// Post Setup processes
37+
/// Systems which handle the processing of asset events for script assets, and dispatching internal script asset events
38+
ScriptAssetDispatch,
39+
/// Systems which read incoming internal script asset events and produce script lifecycle commands
40+
ScriptCommandDispatch,
41+
/// Systems which read incoming script asset events and remove metadata for removed assets
42+
ScriptMetadataRemoval,
43+
44+
/// One time runtime initialization systems
3845
RuntimeInitialization,
3946

40-
// Post Update processes
47+
/// Systems which handle the garbage collection of allocated values
4148
GarbageCollection,
42-
43-
ScriptMetadataInsertion,
44-
ScriptCommandDispatch,
45-
ScriptMetadataRemoval,
4649
}
4750

4851
/// Types which act like scripting plugins, by selecting a context and runtime

0 commit comments

Comments
 (0)