Migration Guide: 0.13 to 0.14-alpha or 0.14 to 0.15
The most important changes to be aware of in this release are:
-
BMS now uses
Handle<ScriptAsset>
as its principle means of referring to scripts as opposed to theScriptId
that was used previously. -
BMS exposes many more choices for deciding how scripts are associated with the contexts in which they run.
-
script_id
is replaced withscript_asset
which now has a type ofHandle<ScriptAsset>
.
Handles
The use of handles for scripts is perhaps the biggest user-facing change. It makes BMS asset usage follow Bevy's conventions. It requires less configuration. It is more idiomatic.
ScriptComponent
Change
In prior versions, ScriptComponent
accepted a vector of ScriptId
s, which was a type alias for Cow<'static, str>
.
-pub struct ScriptComponent(pub Vec<Cow<'static, str>>);
+pub struct ScriptComponent(pub Vec<Handle<ScriptAsset>>);
Because ScriptComponent
accepts handles, it is no longer necessary to store the handles somewhere to prevent the script from unloading. Nor is it necessary to configure an asset path to script id mapper.
ScriptComponent(vec![asset_server.load("foo.lua")])
It is still beneficial to retain script assets in memory, for certain features to work. For example,
script_asset
will not be able to retrieve the asset path of the script if it's not retained.
ScriptId
Change
The ScriptId
has changed from being a string to being an asset ID.
-type ScriptId = Cow<'static, str>
+type ScriptId = AssetId<ScriptAsset>
No Evaluation on Load
In prior versions, BMS would immediately evaluate a ScriptAsset
when it was loaded, and if multiple script assets were loaded, they would be evaluated in non-deterministic order. (See issue #426.) Script assets no longer evaluate immediately. Script assets are only evaluated when their handles are added to a ScriptComponent
or they are added to StaticScripts
.
In addition when a ScriptComponent
loads its scripts, it loads them sequentially.
ScriptAssetSettings
Removed
The ScriptAssetSettings
has been removed. Let us address each of its fields in turn.
script_id_mapper
See AssetPathToScriptIdMapper
section.
extension_to_language_map
and supported_extensions
This is now represented by the LanguageExtensions
resource, which can be configured directly during initialization
pub struct LanguageExtensions(HashMap<&'static str, Language>);
or by the ConfigureScriptAssetSettings
trait:
app.add_supported_script_extensions(&["p8lua"], Language::Lua);
In addition one can configure the language of an asset when it is loaded:
asset_server.load_with_settings("hello.p8lua", |settings: &mut ScriptSettings| {
settings.language = Some(Language::Lua);
});
or when it is created:
let content = String::from("x = 0");
let mut script = ScriptAsset::from(content);
script.language = Language::Lua;
ScriptMetadata
and ScriptMetadataStore
Removed
These were present to associate the previous ScriptId
with the asset ID and language.
That is no longer necessary as the ScriptAsset
knows its own language.
pub struct ScriptAsset {
/// The body of the script
pub content: Box<[u8]>,
/// The language of the script
pub language: Language,
}
AssetPathToScriptIdMapper
Removed
No mapper is necessary between a script and a script ID. If you have a script handle, you have its script ID
let handle: Handle<ScriptAsset> = ...;
let script_id: ScriptId = handle.id(); // ScriptId = AssetId<ScriptAsset>
and vice versa.
let script_id: ScriptId = ...;
let handle: Handle<ScriptAsset> = Handle::Weak(script_id);
Contexts
Choosing how scripts run is a big policy decision. Previously BMS had two options:
- Each script ran in its own context.
- All scripts ran in one context.
This was controlled by the enable_context_sharing()
method on
ConfigureScriptPlugin
. That function is now deprecated. Instead use the set_context_policy
method:
app.add_plugins(LuaScriptingPlugin::default().set_context_policy(
ContextPolicy::shared(),
));
The reason for this change is there are many more choices than before, namely:
ContextPolicy::shared()
ContextPolicy::per_script()
ContextPolicy::per_entity()
ContextPolicy::per_entity_and_script()
See Contexts for more information.
ContextKey
Added
Previously BMS used a ScriptId
and sometimes an Entity
to refer to a
context. If there was no entity then Entity::from_raw(0)
was used. Instead BMS
now uses this ContextKey
to look up contexts.
pub struct ContextKey {
/// Entity if there is one.
pub entity: Option<Entity>,
/// Script ID if there is one.
pub script_id: Option<Handle<ScriptAsset>>
}
This change affects the parameters for the context_pre_handling_initializers
- context_pre_handling_initializers: vec![|script_id, entity, context| {
+ context_pre_handling_initializers: vec![|context_key, context| {
and context_initializers
:
- context_initializers: vec![|script_id, context| {
+ context_initializers: vec![|context_key, context| {
Recipients
Changes
The Recipients
enum now looks like this:
#[derive(Clone, Debug)]
pub enum Recipients {
/// The event needs to be handled by all scripts, if multiple scripts share a context, the event will be sent once per script in the context.
AllScripts,
/// The event is to be handled by all unique contexts, i.e. if two scripts share the same context, the event will be sent only once per the context.
AllContexts,
/// The event is to be handled by a specific script-entity pair
ScriptEntity(ScriptId, Entity),
/// the event is to be handled by a specific static script
StaticScript(ScriptId),
}
This aligns with how scripts are associated with contexts better.
ScriptCallbackEvent
changes
The language for recipients is now controlled through the language
field of the ScriptCallbackEvent
. This allows for more flexibility in how callbacks are handled, especially when multiple languages are involved.
If no language is specified, the callback will apply to all languages.
#[derive(Clone, Event, Debug)]
#[non_exhaustive]
pub struct ScriptCallbackEvent {
/// The label of the callback
pub label: CallbackLabel,
/// The recipients of the callback
pub recipients: Recipients,
/// The language of the callback, if unspecified will apply to all languages
+ pub language: Option<Language>
/// The arguments to the callback
pub args: Vec<ScriptValue>,
/// Whether the callback should emit a response event
pub trigger_response: bool,
}
Bindings Changes
ScriptId
script_id
is replaced with script_asset
which now has a type of Handle<ScriptAsset>
. This means that you can no longer use a string to refer to a script, but rather you must use a handle.
Scripts can still access the asset path of the script using:
-- prints: "my_script.lua"
print(script_asset:asset_path())
ScriptAttachment
The concept of script attachments has been introduced to describe the idea of a script instance. Previously this was muddied due to the fact script ID's were the primary way to refer to scripts. Now the instance of a script and its mapping to a context is clearer.
This is reflected in a brand new set of bindings:
-- will create backing ScriptAttachment instances, that can be used in other bindings.
local entity_script = ScriptAttachment.new_entity_script(entity, script_asset)
local static_script = ScriptAttachment.new_static_script(script_asset)
System Builder
the system builder no longer accepts script id's as parameters. Instead it accepts script attachments
-system_builder("my_callback", "this_script_id.lua")
+system_builder("my_callback", ScriptAttachment.new_static_script(script_asset))