Skip to content

Commit 21c3158

Browse files
authored
fix: add missing extensions in the asset loader (#254)
* fix: fix missing extensions in the asset loader * Actually call `finish` on script plugins and add appropriate docs
1 parent b863175 commit 21c3158

File tree

5 files changed

+120
-6
lines changed

5 files changed

+120
-6
lines changed

crates/bevy_mod_scripting_core/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ derivative = "2.2"
4343
profiling = { workspace = true }
4444
[dev-dependencies]
4545
test_utils = { workspace = true }
46+
tokio = { version = "1", features = ["rt", "macros"] }
4647

4748
[lints]
4849
workspace = true

crates/bevy_mod_scripting_core/src/asset.rs

+8
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ pub struct ScriptAssetSettings {
112112
pub script_id_mapper: AssetPathToScriptIdMapper,
113113
/// Strategies for mapping asset paths to languages
114114
pub script_language_mappers: Vec<AssetPathToLanguageMapper>,
115+
116+
/// The currently supported asset extensions
117+
/// Should be updated by each scripting plugin to include the extensions it supports.
118+
///
119+
/// Will be used to populate the script asset loader with the supported extensions
120+
pub supported_extensions: &'static [&'static str],
115121
}
116122

117123
impl ScriptAssetSettings {
@@ -136,6 +142,7 @@ impl Default for ScriptAssetSettings {
136142
map: (|path: &AssetPath| path.path().to_string_lossy().into_owned().into()),
137143
},
138144
script_language_mappers: vec![],
145+
supported_extensions: &[],
139146
}
140147
}
141148
}
@@ -374,6 +381,7 @@ mod tests {
374381

375382
fn make_test_settings() -> ScriptAssetSettings {
376383
ScriptAssetSettings {
384+
supported_extensions: &[],
377385
script_id_mapper: AssetPathToScriptIdMapper {
378386
map: |path| path.path().to_string_lossy().into_owned().into(),
379387
},

crates/bevy_mod_scripting_core/src/lib.rs

+101-6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ pub enum ScriptingSystemSet {
5555

5656
/// Types which act like scripting plugins, by selecting a context and runtime
5757
/// Each individual combination of context and runtime has specific infrastructure built for it and does not interact with other scripting plugins
58+
///
59+
/// When implementing a new scripting plugin, also ensure the following implementations exist:
60+
/// - [`Plugin`] for the plugin, both [`Plugin::build`] and [`Plugin::finish`] methods need to be dispatched to the underlying [`ScriptingPlugin`] struct
61+
/// - [`AsMut<ScriptingPlugin<Self>`] for the plugin struct
5862
pub trait IntoScriptPluginParams: 'static {
5963
/// The language of the scripts
6064
const LANGUAGE: Language;
@@ -85,6 +89,9 @@ pub struct ScriptingPlugin<P: IntoScriptPluginParams> {
8589
pub context_initializers: Vec<ContextInitializer<P>>,
8690
/// initializers for the contexts run every time before handling events
8791
pub context_pre_handling_initializers: Vec<ContextPreHandlingInitializer<P>>,
92+
93+
/// Supported extensions to be added to the asset settings without the dot
94+
pub supported_extensions: &'static [&'static str],
8895
}
8996

9097
impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
@@ -107,6 +114,8 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
107114
register_script_plugin_systems::<P>(app);
108115
once_per_app_init(app);
109116

117+
app.add_supported_script_extensions(self.supported_extensions);
118+
110119
app.world_mut()
111120
.resource_mut::<ScriptAssetSettings>()
112121
.as_mut()
@@ -115,6 +124,10 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
115124

116125
register_types(app);
117126
}
127+
128+
fn finish(&self, app: &mut App) {
129+
once_per_app_finalize(app);
130+
}
118131
}
119132

120133
impl<P: IntoScriptPluginParams> ScriptingPlugin<P> {
@@ -197,6 +210,33 @@ impl<P: IntoScriptPluginParams + AsMut<ScriptingPlugin<P>>> ConfigureScriptPlugi
197210
}
198211
}
199212

213+
fn once_per_app_finalize(app: &mut App) {
214+
#[derive(Resource)]
215+
struct BMSFinalized;
216+
217+
if app.world().contains_resource::<BMSFinalized>() {
218+
return;
219+
}
220+
app.insert_resource(BMSFinalized);
221+
222+
// read extensions from asset settings
223+
let asset_settings_extensions = app
224+
.world_mut()
225+
.get_resource_or_init::<ScriptAssetSettings>()
226+
.supported_extensions;
227+
228+
// convert extensions to static array
229+
bevy::log::info!(
230+
"Initializing BMS with Supported extensions: {:?}",
231+
asset_settings_extensions
232+
);
233+
234+
app.register_asset_loader(ScriptAssetLoader {
235+
extensions: asset_settings_extensions,
236+
preprocessor: None,
237+
});
238+
}
239+
200240
// One of registration of things that need to be done only once per app
201241
fn once_per_app_init(app: &mut App) {
202242
#[derive(Resource)]
@@ -205,19 +245,14 @@ fn once_per_app_init(app: &mut App) {
205245
if app.world().contains_resource::<BMSInitialized>() {
206246
return;
207247
}
208-
209248
app.insert_resource(BMSInitialized);
210249

211250
app.add_event::<ScriptErrorEvent>()
212251
.add_event::<ScriptCallbackEvent>()
213252
.init_resource::<AppReflectAllocator>()
214253
.init_resource::<Scripts>()
215254
.init_asset::<ScriptAsset>()
216-
.init_resource::<AppScriptFunctionRegistry>()
217-
.register_asset_loader(ScriptAssetLoader {
218-
extensions: &[],
219-
preprocessor: None,
220-
});
255+
.init_resource::<AppScriptFunctionRegistry>();
221256

222257
app.add_systems(
223258
PostUpdate,
@@ -274,3 +309,63 @@ impl AddRuntimeInitializer for App {
274309
self
275310
}
276311
}
312+
313+
/// Trait for adding a supported extension to the script asset settings.
314+
///
315+
/// This is only valid in the plugin building phase, as the asset loader will be created in the `finalize` phase.
316+
/// Any changes to the asset settings after that will not be reflected in the asset loader.
317+
pub trait ConfigureScriptAssetSettings {
318+
/// Adds a supported extension to the asset settings
319+
fn add_supported_script_extensions(&mut self, extensions: &[&'static str]) -> &mut Self;
320+
}
321+
322+
impl ConfigureScriptAssetSettings for App {
323+
fn add_supported_script_extensions(&mut self, extensions: &[&'static str]) -> &mut Self {
324+
let mut asset_settings = self
325+
.world_mut()
326+
.get_resource_or_init::<ScriptAssetSettings>();
327+
328+
let mut new_arr = Vec::from(asset_settings.supported_extensions);
329+
330+
new_arr.extend(extensions);
331+
332+
let new_arr_static = Vec::leak(new_arr);
333+
334+
asset_settings.supported_extensions = new_arr_static;
335+
336+
self
337+
}
338+
}
339+
340+
#[cfg(test)]
341+
mod test {
342+
use super::*;
343+
344+
#[tokio::test]
345+
async fn test_asset_extensions_correctly_accumulate() {
346+
let mut app = App::new();
347+
app.init_resource::<ScriptAssetSettings>();
348+
app.add_plugins(AssetPlugin::default());
349+
350+
app.world_mut()
351+
.resource_mut::<ScriptAssetSettings>()
352+
.supported_extensions = &["lua", "rhai"];
353+
354+
once_per_app_finalize(&mut app);
355+
356+
let asset_loader = app
357+
.world()
358+
.get_resource::<AssetServer>()
359+
.expect("Asset loader not found");
360+
361+
asset_loader
362+
.get_asset_loader_with_extension("lua")
363+
.await
364+
.expect("Lua loader not found");
365+
366+
asset_loader
367+
.get_asset_loader_with_extension("rhai")
368+
.await
369+
.expect("Rhai loader not found");
370+
}
371+
}

crates/languages/bevy_mod_scripting_lua/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ impl Default for LuaScriptingPlugin {
134134
.map_err(ScriptError::from_mlua_error)?;
135135
Ok(())
136136
}],
137+
supported_extensions: &["lua"],
137138
},
138139
}
139140
}
@@ -150,6 +151,10 @@ impl Plugin for LuaScriptingPlugin {
150151
fn build(&self, app: &mut bevy::prelude::App) {
151152
self.scripting_plugin.build(app);
152153
}
154+
155+
fn finish(&self, app: &mut bevy::app::App) {
156+
self.scripting_plugin.finish(app);
157+
}
153158
}
154159
#[profiling::function]
155160
/// Load a lua context from a script

crates/languages/bevy_mod_scripting_rhai/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ impl Default for RhaiScriptingPlugin {
155155
context.scope.set_or_push("script_id", script.to_owned());
156156
Ok(())
157157
}],
158+
supported_extensions: &["rhai"],
158159
},
159160
}
160161
}
@@ -171,6 +172,10 @@ impl Plugin for RhaiScriptingPlugin {
171172
fn build(&self, app: &mut bevy::prelude::App) {
172173
self.scripting_plugin.build(app);
173174
}
175+
176+
fn finish(&self, app: &mut bevy::app::App) {
177+
self.scripting_plugin.finish(app);
178+
}
174179
}
175180

176181
/// Load a rhai context from a script.

0 commit comments

Comments
 (0)