Migrating from 0.23 to 0.24
Scripts
The only globals left are import_namespace, export_namespace and register_callback. Everything else, world included, is imported from a namespace, see Namespaces:
+ local world = import_namespace("bms").world
world.spawn()
Types (Vec3, Transform, and the deprecated types table) are imported from their namespace. Bevy types are grouped by category (math, ecs, transform, ui, …), BMS’ types live in bms:
- local t = Transform.from_translation(Vec3.new(1, 2, 3))
+ local Vec3 = import_namespace("math").Vec3
+ local Transform = import_namespace("transform").Transform
+ local t = Transform.from_translation(Vec3.new(1, 2, 3))
BMS’ functions moved to bms: construct, system_builder, run_script_callback, queue_script_callback, pack_args, unpack_args and log_*. entity and script_asset are now functions:
+ local bms = import_namespace("bms")
- log_info("hi")
+ bms.log_info("hi")
- world.despawn(entity)
+ world.despawn(bms.current_entity())
- script_asset
+ bms.current_script()
Query results are plain lists of the entity followed by the components, result:entity() and result:components() are removed:
for _, result in pairs(world.query():component(Transform):build()) do
- local entity, transform = result:entity(), result:components()[1]
+ local entity, transform = result[1], result[2]
end
Other changes:
world.get_type_by_nameonly takes full paths, i.e."bevy_transform::components::transform::Transform"or"script.my_game.Enemy".- Numbers work on the left of operators:
2 * v,1 - v(dispatched tomul,rsub, …), in Rhai too.
Rust
- Script globals are removed (
AppScriptGlobalsRegistry,#[script_globals],register_static*,GlobalNamespace,FunctionScope::Global,DummyScriptFunctionRegistry,use_dummy_registry, …). Put functions in a namespace instead:
Values go in#[script_bindings(namespace = "my_game")] impl NamespaceMembers { /// `import_namespace("my_game").spawn_enemy(5)` in scripts fn spawn_enemy(ctxt: FunctionCallContext, hp: usize) -> Result<(), InteropError> { .. } }AppScriptNamespaceMembers::register_value, made each time the namespace is imported. - Types with bindings from the bevy crates are in category namespaces. Move a type with
app.override_script_namespace. - Registering a function name twice replaces it, there are no overloads (
overwrite*,iter_overloads,remove_all_overloadsare removed). Take aUnionorScriptValuefor arguments of different types. #[derive(ScriptType)]implements everything a type needs to be used directly in function signatures (FromScript,IntoScript,ArgMeta,GetTypeDependencies,TypedThrough). Use#[script_type(from = custom)]/(into = custom)for a hand written conversion.- Renames:
Namespace→FunctionScope,IntoNamespace→IntoFunctionScope,FromScriptRef/IntoScriptRef→FromScriptErased/IntoScriptErased,try_call_overloads→call_operator. - Functions on
StaticTypeReftakeStaticTypeRefinstead ofV<StaticTypeRef>. ScriptFunctionRegistryis keyed byTypeIdinstead ofFunctionScope:register(type_id, ..),get_function(type_id, name),iter_namespace→iter_type.- Values allocated for scripts are owned by the references to them and freed with the last one, the allocator is removed (
ReflectAllocator,AppReflectAllocator,WorldExtensions::allocator,AllocatorDiagnosticPlugin,ScriptingSystemSet::GarbageCollection,InteropError::GarbageCollectedAllocation). Drop the allocator argument:// before let reference = ReflectReference::new_allocated(value, &mut world.allocator().write()); // after let reference = ReflectReference::new_allocated(value);new_allocated_boxedandnew_allocated_boxed_parial_reflectchange the same way. ScriptLoadingPipeline::time_budget: Option<Duration>is replaced bytick_budget: Option<usize>, the maximum amount of pipeline steps per frame, unlimited by default.ActiveMachines::budgetandRunProcessingPipelineOnce::newtake the same step count.ScriptAttachedMessage(a)/ScriptDetachedMessage(a)are one message,ScriptLifecycleMessage::Attached(a)/::Detached(a), so attachments and detachments are processed in the order they were written.GetScriptHandle::get_script_handlereturns anOption(None: the event doesn’t wait for its script to load) andScriptLifecycleQueue::get_ready, formerly known asLoadedWithHandlesyields(event, Option<(StrongScriptHandle, Language)>).- An attachment whose script is still loading holds back the attachments and detachments after it, and callbacks reach scripts in a deterministic order (attachment order, until scripts are removed), see Determinism. Lua’s
math.randomis seeded with0in new contexts. - Script systems are identified by attachment and callback label (adding one again replaces it) and are removed with their script.
ScriptSystemSetholds a recycled slot instead of the callback label,ScriptSystemBuilderno longer implementsIntoSystem(useScriptSystemBuilder::build), and their errors are sent asScriptErrorMessages instead of being logged.WorldAccessGuard::new_non_exclusivetakes anOption<Arc<ArchetypeFilter>>, restricting component accesses to the given archetypes (Nonefor no restriction). - Script system parameters are declared to Bevy as they’re accessed:
resourceand querycomponents as writes (they were declared as reads, or as accessing nothing for resources, while scripts could write them),resource_read/component_readas reads. Script systems writing the same resources or components no longer run in parallel.ScriptQueryBuilder::as_query_statetakes aQueryAccess:Declareddeclares the written components as written (for queries reported to the scheduler),MatchOnlydeclares all components as read (i.e. forEntityRefqueries only finding entities). - Script systems are put in and ordered against system set values (
ReflectSystemSet) instead of names: scripts register sets withworld.register_new_system_set(namespace, name), Rust sets are registered into a namespace withapp.register_script_system_set(namespace, name, set)(ScriptSystemSetAppExt, now inbevy_mod_scripting_bindings), both are found withworld.get_system_set_by_name.ScriptSystemBuilder::{in_set, before_set, after_set}take aSystemSet.ReflectSystemSetis opaque, and only its set nodes of a schedule graph have a node id. ScriptQueryResultconverts to a list instead of a reference, its script functions are removed.ScriptQueryResult::componentsis aVec<Option<ReflectReference>>,Nonefor absent optional components.ArchetypeFilter::allow/is_allowedandWorldAccessGuard::check_archetype_accesstake whether the component is written.AccessByteSet::from_allowed_lists(read_write, read_only)creates subsets with read only accesses. At most 63 accesses to the same value can be claimed at once, claims beyond fail (the count used to overflow).WorldAccessRange::Externalholds the value’s owner (AccessOwner) instead of an id, and the access map keeps it alive until the claim is released. Build it from the value ((&allocation_id).into());WorldAccessRangeis no longerCopy.
Language implementations
- Dispatch every script operation through
bevy_mod_scripting_bindings::dispatch(index,set_index,static_index,binary,unary,len,iter,display,debug), see Necessary Features.WorldExtensions::lookup_function,lookup_instance_function,lookup_type_functionandlookup_reserved_functionare private. - Convert the new
ScriptValue::Type(TypeId), a type itself (whatworldandStaticTypeRefare). - Set
bindings::builtins::builtins()(import_namespace,export_namespace) and yourregister_callbackas globals, nothing else. Don’t setworld,entityorscript_assetanymore. LuaStaticReflectReference/RhaiStaticReflectReferenceareLuaTypeRef/RhaiTypeRef.
Documentation tooling
- The Lua language server files are split per namespace (
bindings.d.lua,bindings.<namespace>.d.lua, pointworkspace.libraryat the directory), classes are named after their namespace (math.Vec3), and generic types are declared once (Handle<Image>, needs LuaLS 3.17+). cargo xtask docgenis replaced bycargo xtask docs(all binding features,--test-bindingsfor the script test functions).cargo xtask bless-ladupdates the LAD test fixtures.ThroughTypeInfois flat (ThroughTypeInfo::Vec(..),ThroughTypeInfo::Ref(type_info)),ThroughTypeInfo::TypeInfoisOpaque.#[derive(TypedThrough)]documents a type as opaque,#[typed_through(value)]as a value.- LAD:
LadFieldOrVariableKind→LadTypeKind;globalsis removed, builtin functions areLadFunctionNamespace::Global(the mdbook “Globals” and “Functions” pages are one “Builtins” page), namespaces havevalues(add_instance*→add_namespace_value_of/add_namespace_instance); newnamespaces,generic_types,LadTypeDefinition::generic_type,LadFunction::receiver,LadFunctionMetadata::operator(replacesis_operator); arguments are always named and never include the call context;polymorphizied_typesis removed.ArgumentVisitorhas anOutputtype andvisit_*methods.