Skip to content

Commit 7ca94df

Browse files
authored
feat: Add missing luau extension, improve extension configuration options (#366)
# Summary Replaces the mapper struct with a hash map, improves the `App` and `ScriptPlugin` traits so that one can choose to add additional extensions easilly in a predictable place either via: *App* ```rust app.add_supported_script_extensions(self.additional_supported_extensions, self.language.clone()); ``` or *ScriptingPlugin* ```rust app.add_plugins( LuaScriptingPlugin.set_additional_supported_extensions(&["my_ext"]) ) ``` Also adds a bunch of docs
1 parent 9033243 commit 7ca94df

File tree

12 files changed

+238
-102
lines changed

12 files changed

+238
-102
lines changed

crates/bevy_mod_scripting_core/src/asset.rs

+24-49
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ use bevy::{
1616
ResMut,
1717
},
1818
reflect::TypePath,
19-
utils::HashMap,
19+
utils::hashbrown::HashMap,
2020
};
2121
use std::borrow::Cow;
2222

2323
/// Represents a scripting language. Languages which compile into another language should use the target language as their language.
24-
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
24+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
2525
pub enum Language {
2626
/// The Rhai scripting language
2727
Rhai,
@@ -32,6 +32,7 @@ pub enum Language {
3232
/// An external scripting language
3333
External(Cow<'static, str>),
3434
/// Set if none of the asset path to language mappers match
35+
#[default]
3536
Unknown,
3637
}
3738

@@ -110,8 +111,8 @@ impl AssetLoader for ScriptAssetLoader {
110111
pub struct ScriptAssetSettings {
111112
/// Strategy for mapping asset paths to script ids, by default this is the identity function
112113
pub script_id_mapper: AssetPathToScriptIdMapper,
113-
/// Strategies for mapping asset paths to languages
114-
pub script_language_mappers: Vec<AssetPathToLanguageMapper>,
114+
/// Mapping from extension to script language
115+
pub extension_to_language_map: HashMap<&'static str, Language>,
115116

116117
/// The currently supported asset extensions
117118
/// Should be updated by each scripting plugin to include the extensions it supports.
@@ -123,15 +124,15 @@ pub struct ScriptAssetSettings {
123124
impl ScriptAssetSettings {
124125
/// Selects the language for a given asset path
125126
pub fn select_script_language(&self, path: &AssetPath) -> Language {
126-
for mapper in &self.script_language_mappers {
127-
let language = (mapper.map)(path);
128-
match language {
129-
Language::Unknown => continue,
130-
_ => return language,
131-
}
132-
}
133-
134-
Language::Unknown
127+
let extension = path
128+
.path()
129+
.extension()
130+
.and_then(|ext| ext.to_str())
131+
.unwrap_or_default();
132+
self.extension_to_language_map
133+
.get(extension)
134+
.cloned()
135+
.unwrap_or_default()
135136
}
136137
}
137138

@@ -141,7 +142,12 @@ impl Default for ScriptAssetSettings {
141142
script_id_mapper: AssetPathToScriptIdMapper {
142143
map: (|path: &AssetPath| path.path().to_string_lossy().into_owned().into()),
143144
},
144-
script_language_mappers: vec![],
145+
extension_to_language_map: HashMap::from_iter(vec![
146+
("lua", Language::Lua),
147+
("luau", Language::Lua),
148+
("rhai", Language::Rhai),
149+
("rn", Language::Rune),
150+
]),
145151
supported_extensions: &[],
146152
}
147153
}
@@ -154,21 +160,6 @@ pub struct AssetPathToScriptIdMapper {
154160
pub map: fn(&AssetPath) -> ScriptId,
155161
}
156162

157-
#[derive(Clone, Copy)]
158-
/// Strategy for mapping asset paths to languages
159-
pub struct AssetPathToLanguageMapper {
160-
/// The mapping function
161-
pub map: fn(&AssetPath) -> Language,
162-
}
163-
164-
impl Default for AssetPathToLanguageMapper {
165-
fn default() -> Self {
166-
Self {
167-
map: |_| Language::Unknown,
168-
}
169-
}
170-
}
171-
172163
/// A cache of asset id's to their script id's. Necessary since when we drop an asset we won't have the ability to get the path from the asset.
173164
#[derive(Default, Debug, Resource)]
174165
pub struct ScriptMetadataStore {
@@ -393,26 +384,10 @@ mod tests {
393384
script_id_mapper: AssetPathToScriptIdMapper {
394385
map: |path| path.path().to_string_lossy().into_owned().into(),
395386
},
396-
script_language_mappers: vec![
397-
AssetPathToLanguageMapper {
398-
map: |path| {
399-
if path.path().extension().unwrap() == "lua" {
400-
Language::Lua
401-
} else {
402-
Language::Unknown
403-
}
404-
},
405-
},
406-
AssetPathToLanguageMapper {
407-
map: |path| {
408-
if path.path().extension().unwrap() == "rhai" {
409-
Language::Rhai
410-
} else {
411-
Language::Unknown
412-
}
413-
},
414-
},
415-
],
387+
extension_to_language_map: HashMap::from_iter(vec![
388+
("lua", Language::Lua),
389+
("rhai", Language::Rhai),
390+
]),
416391
}
417392
}
418393

crates/bevy_mod_scripting_core/src/lib.rs

+42-18
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
55
use crate::event::ScriptErrorEvent;
66
use asset::{
7-
configure_asset_systems, configure_asset_systems_for_plugin, AssetPathToLanguageMapper,
8-
Language, ScriptAsset, ScriptAssetLoader, ScriptAssetSettings,
7+
configure_asset_systems, configure_asset_systems_for_plugin, Language, ScriptAsset,
8+
ScriptAssetLoader, ScriptAssetSettings,
99
};
1010
use bevy::prelude::*;
1111
use bindings::{
@@ -87,16 +87,16 @@ pub struct ScriptingPlugin<P: IntoScriptPluginParams> {
8787
/// The strategy for assigning contexts to scripts
8888
pub context_assignment_strategy: ContextAssignmentStrategy,
8989

90-
/// The asset path to language mapper for the plugin
91-
pub language_mapper: AssetPathToLanguageMapper,
90+
/// The language this plugin declares
91+
pub language: Language,
92+
/// Supported extensions to be added to the asset settings without the dot
93+
/// By default BMS populates a set of extensions for the languages it supports.
94+
pub additional_supported_extensions: &'static [&'static str],
9295

9396
/// initializers for the contexts, run when loading the script
9497
pub context_initializers: Vec<ContextInitializer<P>>,
9598
/// initializers for the contexts run every time before handling events
9699
pub context_pre_handling_initializers: Vec<ContextPreHandlingInitializer<P>>,
97-
98-
/// Supported extensions to be added to the asset settings without the dot
99-
pub supported_extensions: &'static [&'static str],
100100
}
101101

102102
impl<P: IntoScriptPluginParams> Default for ScriptingPlugin<P> {
@@ -106,10 +106,10 @@ impl<P: IntoScriptPluginParams> Default for ScriptingPlugin<P> {
106106
callback_handler: CallbackSettings::<P>::default().callback_handler,
107107
context_builder: Default::default(),
108108
context_assignment_strategy: Default::default(),
109-
language_mapper: Default::default(),
109+
language: Default::default(),
110110
context_initializers: Default::default(),
111111
context_pre_handling_initializers: Default::default(),
112-
supported_extensions: Default::default(),
112+
additional_supported_extensions: Default::default(),
113113
}
114114
}
115115
}
@@ -136,13 +136,12 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
136136
// add extension for the language to the asset loader
137137
once_per_app_init(app);
138138

139-
app.add_supported_script_extensions(self.supported_extensions);
140-
141-
app.world_mut()
142-
.resource_mut::<ScriptAssetSettings>()
143-
.as_mut()
144-
.script_language_mappers
145-
.push(self.language_mapper);
139+
if !self.additional_supported_extensions.is_empty() {
140+
app.add_supported_script_extensions(
141+
self.additional_supported_extensions,
142+
self.language.clone(),
143+
);
144+
}
146145

147146
register_types(app);
148147
}
@@ -203,6 +202,11 @@ pub trait ConfigureScriptPlugin {
203202
/// This means that all scripts will share the same context. This is useful for when you want to share data between scripts easilly.
204203
/// Be careful however as this also means that scripts can interfere with each other in unexpected ways! Including overwriting each other's handlers.
205204
fn enable_context_sharing(self) -> Self;
205+
206+
/// Set the set of extensions to be added for the plugin's language.
207+
///
208+
/// This is useful for adding extensions that are not supported by default by BMS.
209+
fn set_additional_supported_extensions(self, extensions: &'static [&'static str]) -> Self;
206210
}
207211

208212
impl<P: IntoScriptPluginParams + AsMut<ScriptingPlugin<P>>> ConfigureScriptPlugin for P {
@@ -231,6 +235,11 @@ impl<P: IntoScriptPluginParams + AsMut<ScriptingPlugin<P>>> ConfigureScriptPlugi
231235
self.as_mut().context_assignment_strategy = ContextAssignmentStrategy::Global;
232236
self
233237
}
238+
239+
fn set_additional_supported_extensions(mut self, extensions: &'static [&'static str]) -> Self {
240+
self.as_mut().additional_supported_extensions = extensions;
241+
self
242+
}
234243
}
235244

236245
fn once_per_app_finalize(app: &mut App) {
@@ -386,11 +395,21 @@ impl ManageStaticScripts for App {
386395
/// Any changes to the asset settings after that will not be reflected in the asset loader.
387396
pub trait ConfigureScriptAssetSettings {
388397
/// Adds a supported extension to the asset settings
389-
fn add_supported_script_extensions(&mut self, extensions: &[&'static str]) -> &mut Self;
398+
///
399+
/// This is only valid to call in the plugin building phase, as the asset loader will be created in the `finalize` phase.
400+
fn add_supported_script_extensions(
401+
&mut self,
402+
extensions: &[&'static str],
403+
language: Language,
404+
) -> &mut Self;
390405
}
391406

392407
impl ConfigureScriptAssetSettings for App {
393-
fn add_supported_script_extensions(&mut self, extensions: &[&'static str]) -> &mut Self {
408+
fn add_supported_script_extensions(
409+
&mut self,
410+
extensions: &[&'static str],
411+
language: Language,
412+
) -> &mut Self {
394413
let mut asset_settings = self
395414
.world_mut()
396415
.get_resource_or_init::<ScriptAssetSettings>();
@@ -402,6 +421,11 @@ impl ConfigureScriptAssetSettings for App {
402421
let new_arr_static = Vec::leak(new_arr);
403422

404423
asset_settings.supported_extensions = new_arr_static;
424+
for extension in extensions {
425+
asset_settings
426+
.extension_to_language_map
427+
.insert(*extension, language.clone());
428+
}
405429

406430
self
407431
}

crates/languages/bevy_mod_scripting_lua/src/lib.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
//! Lua integration for the bevy_mod_scripting system.
22
use bevy::{
33
app::Plugin,
4-
asset::AssetPath,
54
ecs::{entity::Entity, world::World},
65
};
76
use bevy_mod_scripting_core::{
8-
asset::{AssetPathToLanguageMapper, Language},
7+
asset::Language,
98
bindings::{
109
function::namespace::Namespace, globals::AppScriptGlobalsRegistry,
1110
script_value::ScriptValue, ThreadWorldContainer, WorldContainer,
@@ -60,9 +59,6 @@ impl Default for LuaScriptingPlugin {
6059
load: lua_context_load,
6160
reload: lua_context_reload,
6261
},
63-
language_mapper: AssetPathToLanguageMapper {
64-
map: lua_language_mapper,
65-
},
6662
context_initializers: vec![
6763
|_script_id, context| {
6864
// set the world global
@@ -134,18 +130,12 @@ impl Default for LuaScriptingPlugin {
134130
.map_err(ScriptError::from_mlua_error)?;
135131
Ok(())
136132
}],
137-
supported_extensions: &["lua"],
133+
additional_supported_extensions: &[],
134+
language: Language::Lua,
138135
},
139136
}
140137
}
141138
}
142-
#[profiling::function]
143-
fn lua_language_mapper(path: &AssetPath) -> Language {
144-
match path.path().extension().and_then(|ext| ext.to_str()) {
145-
Some("lua") => Language::Lua,
146-
_ => Language::Unknown,
147-
}
148-
}
149139

150140
impl Plugin for LuaScriptingPlugin {
151141
fn build(&self, app: &mut bevy::prelude::App) {

crates/languages/bevy_mod_scripting_rhai/src/lib.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
33
use bevy::{
44
app::Plugin,
5-
asset::AssetPath,
65
ecs::{entity::Entity, world::World},
76
};
87
use bevy_mod_scripting_core::{
9-
asset::{AssetPathToLanguageMapper, Language},
8+
asset::Language,
109
bindings::{
1110
function::namespace::Namespace, globals::AppScriptGlobalsRegistry,
1211
script_value::ScriptValue, ThreadWorldContainer, WorldContainer,
@@ -84,9 +83,6 @@ impl Default for RhaiScriptingPlugin {
8483
load: rhai_context_load,
8584
reload: rhai_context_reload,
8685
},
87-
language_mapper: AssetPathToLanguageMapper {
88-
map: rhai_language_mapper,
89-
},
9086
context_initializers: vec![
9187
|_, context: &mut RhaiScriptContext| {
9288
context.scope.set_or_push(
@@ -159,19 +155,14 @@ impl Default for RhaiScriptingPlugin {
159155
context.scope.set_or_push("script_id", script.to_owned());
160156
Ok(())
161157
}],
162-
supported_extensions: &["rhai"],
158+
// already supported by BMS core
159+
additional_supported_extensions: &[],
160+
language: Language::Rhai,
163161
},
164162
}
165163
}
166164
}
167165

168-
fn rhai_language_mapper(path: &AssetPath) -> Language {
169-
match path.path().extension().and_then(|ext| ext.to_str()) {
170-
Some("rhai") => Language::Rhai,
171-
_ => Language::Unknown,
172-
}
173-
}
174-
175166
impl Plugin for RhaiScriptingPlugin {
176167
fn build(&self, app: &mut bevy::prelude::App) {
177168
self.scripting_plugin.build(app);

docs/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# Scripting Reference
1717

1818
- [Introduction](./ScriptingReference/introduction.md)
19+
- [Constructing Arbitrary Types](./ScriptingReference/constructing-arbitrary-types.md)
1920
- [Core Bindings](./ScriptingReference/core-api.md)
2021
- [World](./ScriptingReference/world.md)
2122
- [ReflectReference](./ScriptingReference/reflect-reference.md)

0 commit comments

Comments
 (0)