@@ -55,6 +55,10 @@ pub enum ScriptingSystemSet {
55
55
56
56
/// Types which act like scripting plugins, by selecting a context and runtime
57
57
/// 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
58
62
pub trait IntoScriptPluginParams : ' static {
59
63
/// The language of the scripts
60
64
const LANGUAGE : Language ;
@@ -85,6 +89,9 @@ pub struct ScriptingPlugin<P: IntoScriptPluginParams> {
85
89
pub context_initializers : Vec < ContextInitializer < P > > ,
86
90
/// initializers for the contexts run every time before handling events
87
91
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 ] ,
88
95
}
89
96
90
97
impl < P : IntoScriptPluginParams > Plugin for ScriptingPlugin < P > {
@@ -107,6 +114,8 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
107
114
register_script_plugin_systems :: < P > ( app) ;
108
115
once_per_app_init ( app) ;
109
116
117
+ app. add_supported_script_extensions ( self . supported_extensions ) ;
118
+
110
119
app. world_mut ( )
111
120
. resource_mut :: < ScriptAssetSettings > ( )
112
121
. as_mut ( )
@@ -115,6 +124,10 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
115
124
116
125
register_types ( app) ;
117
126
}
127
+
128
+ fn finish ( & self , app : & mut App ) {
129
+ once_per_app_finalize ( app) ;
130
+ }
118
131
}
119
132
120
133
impl < P : IntoScriptPluginParams > ScriptingPlugin < P > {
@@ -197,6 +210,33 @@ impl<P: IntoScriptPluginParams + AsMut<ScriptingPlugin<P>>> ConfigureScriptPlugi
197
210
}
198
211
}
199
212
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
+
200
240
// One of registration of things that need to be done only once per app
201
241
fn once_per_app_init ( app : & mut App ) {
202
242
#[ derive( Resource ) ]
@@ -205,19 +245,14 @@ fn once_per_app_init(app: &mut App) {
205
245
if app. world ( ) . contains_resource :: < BMSInitialized > ( ) {
206
246
return ;
207
247
}
208
-
209
248
app. insert_resource ( BMSInitialized ) ;
210
249
211
250
app. add_event :: < ScriptErrorEvent > ( )
212
251
. add_event :: < ScriptCallbackEvent > ( )
213
252
. init_resource :: < AppReflectAllocator > ( )
214
253
. init_resource :: < Scripts > ( )
215
254
. init_asset :: < ScriptAsset > ( )
216
- . init_resource :: < AppScriptFunctionRegistry > ( )
217
- . register_asset_loader ( ScriptAssetLoader {
218
- extensions : & [ ] ,
219
- preprocessor : None ,
220
- } ) ;
255
+ . init_resource :: < AppScriptFunctionRegistry > ( ) ;
221
256
222
257
app. add_systems (
223
258
PostUpdate ,
@@ -274,3 +309,63 @@ impl AddRuntimeInitializer for App {
274
309
self
275
310
}
276
311
}
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
+ }
0 commit comments