diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa4fb172a3..9082baf651 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,14 @@ name: Check and Lint jobs: check: name: Check - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macOS-latest] steps: - name: Install alsa and udev run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev + if: runner.os == 'linux' - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: @@ -24,7 +28,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: check - args: --features=lua54,teal + args: --workspace --features=lua54,rhai,teal,lua_script_api,rhai_script_api fmt: name: Rustfmt @@ -61,4 +65,4 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: --features=lua54,teal -- -D warnings \ No newline at end of file + args: --features=lua54,rhai,teal,lua_script_api,rhai_script_api -- -D warnings \ No newline at end of file diff --git a/.gitignore b/.gitignore index d78591d4b4..f87106db05 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,6 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk -.vscode/ - **types/ **/doc assets/scripts/tlconfig.lua diff --git a/.vscode/settings.json b/.vscode/settings.json index 845b0a8db1..5a7f27ad19 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,10 @@ "rust-analyzer.cargo.features": [ "lua54", - "teal", + "lua_script_api", + "rhai", + "rhai_script_api", + "teal" ], "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" diff --git a/Cargo.toml b/Cargo.toml index fddbd674f5..8c7fee9eab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.1" authors = ["Maksymilian Mozolewski "] edition = "2021" license = "MIT" -description = "Bevy plugin for enabling scripting" +description = "Multi language scripting in Bevy" repository = "https://github.com/makspll/bevy_mod_scripting" homepage = "https://github.com/makspll/bevy_mod_scripting" keywords = ["bevy", "gamedev", "scripting", "lua"] @@ -16,58 +16,77 @@ include= ["readme.md","/src","/examples","/assets","LICENSE"] name = "bevy_mod_scripting" path = "src/lib.rs" -[package.metadata.docs.rs] -features = ["lua54","teal","unsafe_lua_modules"] - -[package.metadata.release] -enable-features=["lua54"] +[package.metadata."docs.rs"] +features = ["lua","rhai","lua_script_api","rhai_script_api","teal"] [features] +## core +doc_always = ["bevy_mod_scripting_core/doc_always"] + +## lua +lua = ["bevy_mod_scripting_lua"] +# one of these must be selected +lua51 = ["bevy_mod_scripting_lua/lua51", "lua"] +lua52 = ["bevy_mod_scripting_lua/lua52", "lua"] +lua53 = ["bevy_mod_scripting_lua/lua53", "lua"] +lua54 = ["bevy_mod_scripting_lua/lua54", "lua"] +luajit = ["bevy_mod_scripting_lua/luajit", "lua"] +luajit52 = ["bevy_mod_scripting_lua/luajit52", "lua"] + +# optional +lua_script_api=["bevy_script_api/lua"] +unsafe_lua_modules=["bevy_mod_scripting_lua/unsafe_lua_modules"] +teal = ["bevy_mod_scripting_lua/teal"] +mlua_serialize = ["bevy_mod_scripting_lua/mlua_serialize"] +mlua_macros = ["bevy_mod_scripting_lua/mlua_macros"] + +## rhai +rhai = ["bevy_mod_scripting_rhai"] +rhai_script_api=["bevy_script_api/rhai"] -# if enabled enables documentation updating in optimized builds -doc_always = [] +[dependencies] +bevy_mod_scripting_core = { path = "bevy_mod_scripting_core", version = "0.1.1" } +bevy_mod_scripting_lua = { path = "languages/bevy_mod_scripting_lua", version = "0.1.1", optional = true } +bevy_mod_scripting_rhai = { path = "languages/bevy_mod_scripting_rhai", version = "0.1.1", optional = true} +bevy_script_api = { path = "bevy_script_api", version = "0.1.1", optional = true } -# enables loading possibly unsafe lua modules by lua scripts -unsafe_lua_modules = [] +[dev-dependencies] +bevy = { version = "0.8.0"} +rand = "0.8.5" -# enable teal utilities -teal = [] +# bevy_console = { git = "https://github.com/OnlyGraphs/bevy-console" } +# bevy_asset_loader = {git = "https://github.com/NiklasEi/bevy_asset_loader", features = ["dynamic_assets"]} +# bevy_script_api= {path="./bevy_script_api", version="0.1.1", features=["lua","rhai"]} +# bevy_mod_scripting_rhai = {path="languages/bevy_mod_scripting_rhai", version="0.1.1"} +# bevy_mod_scripting_lua = {path="languages/bevy_mod_scripting_lua", version="0.1.1", features=["lua54"]} +# bevy_mod_scripting_lua_derive = {path="languages/bevy_mod_scripting_lua_derive", version="0.1.1"} -lua51 = ["tealr/mlua_lua51"] -lua52 = ["tealr/mlua_lua52"] -lua53 = ["tealr/mlua_lua53"] -lua54 = ["tealr/mlua_lua54"] -luajit = ["tealr/mlua_luajit"] -luajit52 = ["tealr/mlua_luajit52"] +# bevy = { version = "0.8.0"} +# serde = "1.0.137" +# criterion = "0.3" -mlua_serialize = ["tealr/mlua_serialize"] -mlua_macros = ["tealr/mlua_macros"] -[dependencies] -bevy = { version = "0.8.0", default-features = false, features=["bevy_asset","bevy_gltf","bevy_animation","bevy_core_pipeline","bevy_ui","bevy_pbr","bevy_render","bevy_text","bevy_sprite","filesystem_watcher"]} -tealr = { version = "0.9.0-alpha1", features=["mlua_vendored","mlua_send"]} -rhai = { version = "1.7.0", features = ["sync"] } -anyhow = "1.0.57" -once_cell = "1.10.0" -bevy_event_priority = {path = "bevy_event_priority", version = "0.1.1"} -bevy_mod_scripting_derive = {path = "bevy_mod_scripting_derive", version = "0.1.1"} -thiserror = "1.0.31" -lazy_static = "1.4.0" -paste = "1.0.7" -parking_lot = "0.12.1" -serde_json = "1.0.81" -num-traits = "0.2.15" -serde = { version = "1", features = ["derive"] } -smallvec = "1.9.0" +[workspace] +resolver = "2" +members = [ + "bevy_mod_scripting_core", + "bevy_event_priority", + "bevy_mod_scripting_derive", + "bevy_api_gen", + "bevy_script_api", + "languages/bevy_mod_scripting_lua", + "languages/bevy_mod_scripting_lua_derive", + "languages/bevy_mod_scripting_rhai", + # "languages/rhai/derive", + "bevy_mod_scripting_common" +] -[dev-dependencies] -# bevy_console = { git = "https://github.com/OnlyGraphs/bevy-console" } -# bevy_asset_loader = {git = "https://github.com/NiklasEi/bevy_asset_loader", features = ["dynamic_assets"]} -bevy = { version = "0.8.0"} -rand = "0.8.5" -serde = "1.0.137" -criterion = "0.3" +[profile.dev] +opt-level = 1 + +[profile.dev.package."*"] +opt-level = 3 # needs bevy 0.8 support from console @@ -84,45 +103,38 @@ criterion = "0.3" [[example]] name = "complex_game_loop_lua" path = "examples/lua/complex_game_loop.rs" -required-features = ["lua54"] +required-features=["lua54"] [[example]] name = "game_of_life_lua" path = "examples/lua/game_of_life.rs" -required-features = ["lua54","teal"] +required-features=["lua54","teal","lua_script_api"] [[example]] name = "event_recipients_lua" path = "examples/lua/event_recipients.rs" +required-features=["lua54"] [[example]] name = "documentation_gen_lua" path = "examples/lua/documentation_gen.rs" -required-features = ["lua54"] +required-features=["lua54","teal","lua_script_api"] [[example]] name = "bevy_api_lua" path = "examples/lua/bevy_api.rs" -required-features = ["lua54"] +required-features=["lua54","lua_script_api"] + +[[example]] +name = "bevy_api_rhai" +path = "examples/rhai/bevy_api.rs" +required-features=["rhai"] [[example]] name = "wrappers" path = "examples/wrappers.rs" -required-features = ["lua54"] +required-features=["lua54","lua_script_api"] -[workspace] -resolver = "2" -members = [ - "bevy_event_priority", - "bevy_mod_scripting_derive", - "bevy_api_gen" -] - -[profile.dev] -opt-level = 1 - -[profile.dev.package."*"] -opt-level = 3 diff --git a/api_gen_config.toml b/api_gen_config.toml index f71480890d..2ab0860d65 100644 --- a/api_gen_config.toml +++ b/api_gen_config.toml @@ -1,19 +1,28 @@ imports = """ +#[cfg(feature="lua")] +use { + bevy_mod_scripting_lua_derive::impl_lua_newtype, + bevy_mod_scripting_lua::{ + tealr::mlu::mlua::MetaMethod, + docs::LuaDocFragment + }, + crate::lua::RegisterForeignLuaType, +}; use std::ops::*; -use crate::{lua::bevy::{LuaWorld,LuaTypeRegistration,LuaScriptData}, std::LuaVec, DummyTypeName}; -use crate::{impl_tealr_any_union,ReflectionError,ReflectPathElem,RegisterForeignLuaType,ReflectedValue, api::ValueIndex, APIProvider, LuaDocFragment}; +use crate::{script_ref::{ReflectedValue,ValueIndex}, + sub_reflect::ReflectPathElem, + error::ReflectionError +}; use std::sync::Mutex; -use crate::{impl_tealr_generic}; -use tealr::{mlu::{mlua,mlua::{prelude::*,MetaMethod}}}; +use bevy_mod_scripting_core::prelude::*; use bevy::prelude::App; """ other = """ -impl_tealr_generic!(pub(crate) struct T); -impl_tealr_generic!(pub(crate) struct K); -impl_tealr_generic!(pub(crate) struct V); +#[cfg(feature="lua")] +crate::impl_tealr_generic!(pub(crate) struct T); """ primitives = ["usize","isize","f32","f64","u128","u64","u32","u16","u8","i128","i64","i32","i16","i8","String","bool"] @@ -23,29 +32,29 @@ primitives = ["usize","isize","f32","f64","u128","u64","u32","u16","u8","i128"," name="ReflectedValue" [[manual_lua_types]] -name="LuaWorld" +name="crate::lua::bevy::LuaWorld" proxy_name="world" include_global_proxy=true use_dummy_proxy=true [[manual_lua_types]] -name="LuaScriptData" +name="crate::lua::bevy::LuaScriptData" proxy_name="script" include_global_proxy=true use_dummy_proxy=true [[manual_lua_types]] -name="LuaEntity" +name="crate::lua::bevy::LuaEntity" proxy_name="entity" include_global_proxy=true use_dummy_proxy=true dont_process=true [[manual_lua_types]] -name="LuaTypeRegistration" +name="crate::lua::bevy::LuaTypeRegistration" [[manual_lua_types]] -name="LuaVec" +name="crate::lua::std::LuaVec" ## BEVY_UI @@ -142,7 +151,6 @@ type="AnimationPlayer" source="bevy_animation" - ## BEVY_CORE [[types]] @@ -303,7 +311,6 @@ type="PointLightShadowMap" source="bevy_pbr" - [[types]] type="AlphaMode" source="bevy_pbr" @@ -323,7 +330,6 @@ type="Camera3dDepthLoadOp" source="bevy_core_pipeline" - [[types]] type="ClearColor" source="bevy_core_pipeline" @@ -413,9 +419,6 @@ source="bevy_render" type="Msaa" source="bevy_render" - - - [[types]] type="Camera" source="bevy_render" @@ -450,10 +453,6 @@ traits=[ {name="CameraProjection", import_path="bevy::render::camera::CameraProjection"} ] -[[types]] -type="RenderTarget" -source="bevy_render" - [[types]] type="DepthCalculation" source="bevy_render" @@ -483,12 +482,10 @@ source="bevy_asset" type="SourcePathId" source="bevy_asset" - [[types]] type="HandleId" source="bevy_asset" - ## BEVY_MATH [[types]] type="Vec2" @@ -497,7 +494,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f32::vec2::Vec2" +import_path="glam::f32::Vec2" [[types]] type="Vec3" @@ -506,7 +503,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f32::vec3::Vec3" +import_path="glam::f32::Vec3" [[types]] type="Vec3A" @@ -515,7 +512,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f32::sse2::vec3A::Vec3A" +import_path="glam::f32::Vec3A" [[types]] @@ -525,32 +522,32 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f32::sse2::vec4::Vec4" +import_path="glam::f32::Vec4" [[types]] type="BVec2" source="bevy_math" -import_path="glam::f32::sse2::vec2::BVec2" +import_path="glam::bool::BVec2" [[types]] type="BVec3" source="bevy_math" -import_path="glam::f32::sse2::vec3::BVec3" +import_path="glam::bool::BVec3" [[types]] type="BVec4" source="bevy_math" -import_path="glam::f32::sse2::vec4::BVec4" +import_path="glam::bool::BVec4" [[types]] type="BVec3A" source="bevy_math" -import_path="glam::f32::sse2::vec3::BVec3A" +import_path="glam::bool::BVec3A" [[types]] type="BVec4A" source="bevy_math" -import_path="glam::f32::sse2::vec4::BVec4A" +import_path="glam::bool::BVec4A" [[types]] type="DVec2" @@ -559,7 +556,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f64::dvec2::DVec2" +import_path="glam::f64::DVec2" [[types]] type="DVec3" @@ -568,7 +565,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f64::dvec3::DVec3" +import_path="glam::f64::DVec3" [[types]] type="DVec4" @@ -577,7 +574,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::f64::dvec4::DVec4" +import_path="glam::f64::DVec4" [[types]] type="IVec2" @@ -586,7 +583,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::i32::ivec2::IVec2" +import_path="glam::i32::IVec2" [[types]] type="IVec3" @@ -595,7 +592,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::i32::ivec3::IVec3" +import_path="glam::i32::IVec3" [[types]] type="IVec4" @@ -604,7 +601,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::i32::ivec4::IVec4" +import_path="glam::i32::IVec4" [[types]] type="UVec2" @@ -613,7 +610,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::u32::uvec2::UVec2" +import_path="glam::u32::UVec2" [[types]] type="UVec3" @@ -622,7 +619,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::u32::uvec3::UVec3" +import_path="glam::u32::UVec3" [[types]] type="UVec4" @@ -631,7 +628,7 @@ lua_methods=[ "(MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}", "mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}" ] -import_path="glam::u32::uvec4::UVec4" +import_path="glam::u32::UVec4" [[types]] type="Mat3" @@ -662,7 +659,7 @@ lua_methods=[ } """ ] -import_path="glam::f32::mat3::Mat3" +import_path="glam::f32::Mat3" [[types]] type="Mat2" @@ -693,7 +690,7 @@ lua_methods=[ } """ ] -import_path="glam::f32::sse2::mat2::Mat2" +import_path="glam::f32::Mat2" [[types]] @@ -725,7 +722,7 @@ lua_methods=[ } """ ] -import_path="glam::f32::sse2::mat3::Mat3A" +import_path="glam::f32::Mat3A" [[types]] type="Mat4" @@ -756,7 +753,7 @@ lua_methods=[ } """ ] -import_path="glam::f32::sse2::mat4::Mat4" +import_path="glam::f32::Mat4" [[types]] @@ -788,7 +785,7 @@ lua_methods=[ } """ ] -import_path="glam::f64::dmat2::DMat2" +import_path="glam::f64::DMat2" [[types]] type="DMat3" @@ -819,7 +816,7 @@ lua_methods=[ } """ ] -import_path="glam::f64::dmat3::DMat3" +import_path="glam::f64::DMat3" [[types]] type="DMat4" @@ -850,39 +847,39 @@ lua_methods=[ } """ ] -import_path="glam::f64::dmat4::DMat4" +import_path="glam::f64::DMat4" [[types]] type="Affine2" source="bevy_math" -import_path="glam::f32::sse2::mat2::Affine2" +import_path="glam::f32::Affine2" [[types]] type="Affine3A" source="bevy_math" -import_path="glam::f32::sse2::mat3::Affine3A" +import_path="glam::f32::Affine3A" [[types]] type="DAffine2" source="bevy_math" -import_path="glam::f64::sse2::mat2::DAffine2" +import_path="glam::f64::DAffine2" [[types]] type="DAffine3" source="bevy_math" -import_path="glam::f64::sse2::mat3::DAffine3" +import_path="glam::f64::DAffine3" [[types]] type="Quat" source="bevy_math" -import_path="glam::f32::sse2::quat::Quat" +import_path="glam::f32::Quat" [[types]] type="DQuat" source="bevy_math" -import_path="glam::f64::dquat::DQuat" +import_path="glam::f64::DQuat" [[types]] type="EulerRot" source="bevy_math" -import_path="glam::euler::EulerRot" \ No newline at end of file +import_path="glam::EulerRot" \ No newline at end of file diff --git a/bevy_api_gen/Cargo.toml b/bevy_api_gen/Cargo.toml index 62bf4be873..20cb14e2b6 100644 --- a/bevy_api_gen/Cargo.toml +++ b/bevy_api_gen/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.1" authors = ["Maksymilian Mozolewski "] edition = "2021" license = "MIT" -description = "Derive macros for bevy_mod_scripting" -repository = "https://github.com/makspll/bevy_scripting" -homepage = "https://github.com/makspll/bevy_scripting" -keywords = ["bevy", "gamedev", "scripting", "lua"] +description = "A code generator creating macro invocations to support the changing bevy API" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "lua","code-generation"] categories = ["game-development"] -readme = "../readme.md" +readme = "readme.md" [lib] name = "bevy_api_gen_lib" diff --git a/bevy_api_gen/readme.md b/bevy_api_gen/readme.md new file mode 100644 index 0000000000..c6cc619554 --- /dev/null +++ b/bevy_api_gen/readme.md @@ -0,0 +1,3 @@ +# bevy_api_gen + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_api_gen/src/main.rs b/bevy_api_gen/src/main.rs index 84d929df8d..353076314a 100644 --- a/bevy_api_gen/src/main.rs +++ b/bevy_api_gen/src/main.rs @@ -47,7 +47,7 @@ pub(crate) fn generate_macros( source .index .iter() - .filter(|(_, item)| { + .filter(|(_id, item)| { item.name .as_ref() .and_then(|k| config.types.get(k)) @@ -123,9 +123,9 @@ pub(crate) fn generate_macros( // we want to preserve the original ordering from the config file wrapped_items.sort_by_cached_key(|f| config.types.get_index_of(f.wrapped_type).unwrap()); - writer.write_line("#[allow(clippy::all)]"); + writer.write_line("#![allow(clippy::all,unused_imports)]"); writer.write_line("// This file is generated by `bevy_mod_scripting_derive/main.rs` change the template not this file"); - writer.write_line("extern crate self as bevy_mod_scripting;"); + writer.write_line("extern crate self as bevy_script_api;"); writer.write_line("use bevy_mod_scripting_derive::impl_script_newtype;"); // user defined @@ -161,6 +161,7 @@ pub(crate) fn generate_macros( // macro invocation writer.write_no_newline("impl_script_newtype!"); writer.open_brace(); + writer.write_line("#[languages(on_feature(lua))]"); v.write_type_docstring(&mut writer, args); writer.write_indentation(); @@ -170,7 +171,7 @@ pub(crate) fn generate_macros( v.write_derive_flags_body(&config, &mut writer, args); - writer.write_line("impl"); + writer.write_line("lua impl"); writer.open_brace(); v.write_impl_block_body(&mut writer, args); writer.close_brace(); @@ -185,11 +186,16 @@ pub(crate) fn generate_macros( // now create the BevyAPIProvider // first the globals + writer.write_line("#[cfg(feature=\"lua\")]"); writer.write_line("#[derive(Default)]"); writer.write_line("pub(crate) struct BevyAPIGlobals;"); - writer.write_no_newline("impl tealr::mlu::ExportInstances for BevyAPIGlobals"); + + writer.write_line("#[cfg(feature=\"lua\")]"); + writer.write_no_newline( + "impl bevy_mod_scripting_lua::tealr::mlu::ExportInstances for BevyAPIGlobals", + ); writer.open_brace(); - writer.write_line("fn add_instances<'lua, T: tealr::mlu::InstanceCollector<'lua>>(self, instances: &mut T) -> LuaResult<()>"); + writer.write_line("fn add_instances<'lua, T: bevy_mod_scripting_lua::tealr::mlu::InstanceCollector<'lua>>(self, instances: &mut T) -> bevy_mod_scripting_lua::tealr::mlu::mlua::Result<()>"); writer.open_brace(); for (global_name, type_, dummy_proxy) in wrapped_items .iter() @@ -216,13 +222,13 @@ pub(crate) fn generate_macros( writer.write_inline(".into()"); // corresponding proxy if dummy_proxy { - writer.write_inline(", DummyTypeName::<"); + writer.write_inline(", crate::lua::util::DummyTypeName::<"); writer.write_inline(type_); writer.write_inline(">::new"); writer.write_inline(")?;"); writer.newline(); } else { - writer.write_inline(", tealr::mlu::UserDataProxy::<"); + writer.write_inline(", bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::<"); writer.write_inline(type_); writer.write_inline(">::new)?;"); writer.newline(); @@ -234,23 +240,25 @@ pub(crate) fn generate_macros( writer.close_brace(); // then the actual provider + writer.write_line("#[cfg(feature=\"lua\")]"); writer.write_line("pub struct LuaBevyAPIProvider;"); // begin impl { + writer.write_line("#[cfg(feature=\"lua\")]"); writer.write_no_newline("impl APIProvider for LuaBevyAPIProvider"); writer.open_brace(); - writer.write_line("type APITarget = Mutex;"); - writer.write_line("type ScriptContext = Mutex;"); + writer.write_line("type APITarget = Mutex;"); + writer.write_line("type ScriptContext = Mutex;"); writer.write_line("type DocTarget = LuaDocFragment;"); // attach_api { writer.write_no_newline( - "fn attach_api(&mut self, ctx: &mut Self::APITarget) -> Result<(), crate::ScriptError>", + "fn attach_api(&mut self, ctx: &mut Self::APITarget) -> Result<(), ScriptError>", ); writer.open_brace(); writer.write_line("let ctx = ctx.get_mut().expect(\"Unable to acquire lock on Lua context\");"); - writer.write_line("Ok(tealr::mlu::set_global_env(BevyAPIGlobals,&ctx)?)"); + writer.write_line("bevy_mod_scripting_lua::tealr::mlu::set_global_env(BevyAPIGlobals,ctx).map_err(|e| ScriptError::Other(e.to_string()))"); writer.close_brace(); // } attach_api @@ -277,7 +285,9 @@ pub(crate) fn generate_macros( writer.newline(); if include_proxy { - writer.write_no_newline(".process_type::>()"); writer.newline(); diff --git a/bevy_event_priority/Cargo.toml b/bevy_event_priority/Cargo.toml index db201a4a84..7743be45dd 100644 --- a/bevy_event_priority/Cargo.toml +++ b/bevy_event_priority/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/makspll/bevy_mod_scripting" homepage = "https://github.com/makspll/bevy_mod_scripting" keywords = ["bevy", "gamedev", "scripting", "lua"] categories = ["game-development"] -readme = "../readme.md" +readme = "readme.md" [lib] name = "bevy_event_priority" diff --git a/bevy_event_priority/readme.md b/bevy_event_priority/readme.md new file mode 100644 index 0000000000..d29e475621 --- /dev/null +++ b/bevy_event_priority/readme.md @@ -0,0 +1,3 @@ +# bevy_event_priority + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_mod_scripting_common/Cargo.toml b/bevy_mod_scripting_common/Cargo.toml new file mode 100644 index 0000000000..0e2e5cfe86 --- /dev/null +++ b/bevy_mod_scripting_common/Cargo.toml @@ -0,0 +1,26 @@ +[project] +name = "bevy_mod_scripting_common" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Traits and syn structures for language implementors" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "lua"] +categories = ["game-development"] +readme = "readme.md" + +[lib] +name = "bevy_mod_scripting_common" +path = "src/lib.rs" + +[dependencies] +paste = "1.0.7" +syn = {version="1.0.57",features=["full","fold","extra-traits"]} +quote = "1.0.8" +proc-macro2 = "1.0" +convert_case = "0.5.0" +serde = { version = "1.0", features = ["derive"] } +serde_derive = "1.0.137" +indexmap = {version= "1.9.1", features= ["serde"]} diff --git a/bevy_mod_scripting_common/readme.md b/bevy_mod_scripting_common/readme.md new file mode 100644 index 0000000000..674bf81c2c --- /dev/null +++ b/bevy_mod_scripting_common/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_common + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_mod_scripting_derive/src/common/arg.rs b/bevy_mod_scripting_common/src/arg.rs similarity index 91% rename from bevy_mod_scripting_derive/src/common/arg.rs rename to bevy_mod_scripting_common/src/arg.rs index abfbc8faa3..8d2fee9b7f 100644 --- a/bevy_mod_scripting_derive/src/common/arg.rs +++ b/bevy_mod_scripting_common/src/arg.rs @@ -10,7 +10,7 @@ use syn::{ }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) enum SelfType { +pub enum SelfType { Self_, RefSelf, MutSelf, @@ -96,7 +96,7 @@ impl ToTokens for SelfType { } #[derive(PartialEq, Eq, Hash, Debug, Clone)] -pub(crate) enum SimpleType { +pub enum SimpleType { BaseIdent(Ident), Ref { ampersand: Option, @@ -134,11 +134,7 @@ impl SimpleType { pub fn strip_outer_refs(self) -> Self { match self { SimpleType::BaseIdent(_) => self, - SimpleType::Ref { - ampersand, - mut_, - type_, - } => *type_, + SimpleType::Ref { type_, .. } => *type_, } } @@ -180,7 +176,7 @@ impl ToTokens for SimpleType { #[derive(PartialEq, Eq, Hash, Debug)] /// Raw argument expression argument received from the macro invocation -pub(crate) enum ArgType { +pub enum ArgType { Raw { paren: Paren, type_: SimpleType }, Wrapped { paren: Paren, type_: SimpleType }, Self_(SelfType), @@ -206,8 +202,8 @@ impl Parse for ArgType { impl ToTokens for ArgType { fn to_tokens(&self, tokens: &mut TokenStream) { match self { - ArgType::Raw { paren, type_ } => tokens.extend(quote::quote!(Raw(#type_))), - ArgType::Wrapped { paren, type_ } => tokens.extend(quote::quote!(Wrapped(#type_))), + ArgType::Raw { type_, .. } => tokens.extend(quote::quote!(Raw(#type_))), + ArgType::Wrapped { type_, .. } => tokens.extend(quote::quote!(Wrapped(#type_))), ArgType::Self_(s) => s.to_tokens(tokens), }; } @@ -238,16 +234,16 @@ impl ArgType { pub fn is_any_ref(&self) -> bool { match self { - ArgType::Raw { paren, type_ } => type_.is_any_ref(), - ArgType::Wrapped { paren, type_ } => type_.is_any_ref(), + ArgType::Raw { type_, .. } => type_.is_any_ref(), + ArgType::Wrapped { type_, .. } => type_.is_any_ref(), ArgType::Self_(s) => s.is_any_ref(), } } pub fn is_mut_ref(&self) -> bool { match self { - ArgType::Raw { paren, type_ } => type_.is_mut_ref(), - ArgType::Wrapped { paren, type_ } => type_.is_mut_ref(), + ArgType::Raw { type_, .. } => type_.is_mut_ref(), + ArgType::Wrapped { type_, .. } => type_.is_mut_ref(), ArgType::Self_(s) => s.is_mut_ref(), } } diff --git a/bevy_mod_scripting_derive/src/common/derive_flag.rs b/bevy_mod_scripting_common/src/derive_flag.rs similarity index 83% rename from bevy_mod_scripting_derive/src/common/derive_flag.rs rename to bevy_mod_scripting_common/src/derive_flag.rs index 4243b659be..2ba7bebf85 100644 --- a/bevy_mod_scripting_derive/src/common/derive_flag.rs +++ b/bevy_mod_scripting_common/src/derive_flag.rs @@ -1,18 +1,13 @@ -use proc_macro2::Span; +use proc_macro2::{Span, TokenStream}; use syn::{ parenthesized, parse::{Parse, ParseStream}, punctuated::Punctuated, token::Paren, - Attribute, Ident, Member, Token, TypePath, + Attribute, Ident, Member, Token, }; -use crate::{ - lua_method::{LuaMethodType, MethodMacroArg}, - ops::*, - utils::impl_parse_enum, - TokenStream2, -}; +use crate::{ops::*, utils::impl_parse_enum}; use quote::ToTokens; @@ -20,7 +15,7 @@ use super::arg::ArgType; impl_parse_enum!(input,ident: #[derive(PartialEq,Eq,Hash)] -pub(crate) enum DeriveFlag { +pub enum DeriveFlag { /// Tells the implementors this type supports `Debug` Debug => {Ok(Self::Debug{ident})}, @@ -80,31 +75,31 @@ pub(crate) enum DeriveFlag { } ); -#[derive(PartialEq, Eq, Hash, Debug)] -pub(crate) struct MethodMacroInvokation { - pub target: TypePath, - pub arrow: Token![->], - pub identifier: LuaMethodType, - pub paren: Paren, - pub args: Punctuated, -} - -#[allow(clippy::eval_order_dependence)] -impl Parse for MethodMacroInvokation { - fn parse(input: ParseStream) -> Result { - let f; - Ok(Self { - target: input.parse()?, - arrow: input.parse()?, - identifier: input.parse()?, - paren: parenthesized!(f in input), - args: f.parse_terminated(MethodMacroArg::parse)?, - }) - } -} +// #[derive(PartialEq, Eq, Hash, Debug)] +// pub(crate) struct MethodMacroInvokation { +// pub target: TypePath, +// pub arrow: Token![->], +// pub identifier: LuaMethodType, +// pub paren: Paren, +// pub args: Punctuated, +// } + +// #[allow(clippy::eval_order_dependence)] +// impl Parse for MethodMacroInvokation { +// fn parse(input: ParseStream) -> Result { +// let f; +// Ok(Self { +// target: input.parse()?, +// arrow: input.parse()?, +// identifier: input.parse()?, +// paren: parenthesized!(f in input), +// args: f.parse_terminated(MethodMacroArg::parse)?, +// }) +// } +// } #[derive(PartialEq, Eq, Hash)] -pub(crate) struct AutoMethod { +pub struct AutoMethod { pub docstring: Vec, pub ident: Ident, pub paren: Paren, @@ -114,7 +109,7 @@ pub(crate) struct AutoMethod { } impl ToTokens for AutoMethod { - fn to_tokens(&self, tokens: &mut TokenStream2) { + fn to_tokens(&self, tokens: &mut TokenStream) { let docstring = self.docstring.iter(); let id = &self.ident; let args = &self.args; @@ -159,7 +154,7 @@ impl Parse for AutoMethod { } #[derive(PartialEq, Eq, Hash)] -pub(crate) struct AutoFieldAttributes { +pub struct AutoFieldAttributes { pub script_name: Option, } @@ -190,7 +185,7 @@ impl TryFrom<&[Attribute]> for AutoFieldAttributes { } #[derive(PartialEq, Eq, Hash)] -pub(crate) struct AutoField { +pub struct AutoField { pub docstring: Vec, pub attrs: Vec, pub parsed_attrs: AutoFieldAttributes, @@ -215,7 +210,7 @@ impl Parse for AutoField { } impl ToTokens for AutoField { - fn to_tokens(&self, tokens: &mut TokenStream2) { + fn to_tokens(&self, tokens: &mut TokenStream) { let docstring = self.docstring.iter(); let attrs = self.attrs.iter(); let id = &self.member; diff --git a/bevy_mod_scripting_derive/src/common/implementor.rs b/bevy_mod_scripting_common/src/implementor.rs similarity index 82% rename from bevy_mod_scripting_derive/src/common/implementor.rs rename to bevy_mod_scripting_common/src/implementor.rs index 5e7a4bd968..8c83675c28 100644 --- a/bevy_mod_scripting_derive/src/common/implementor.rs +++ b/bevy_mod_scripting_common/src/implementor.rs @@ -2,15 +2,15 @@ use proc_macro2::TokenStream; use quote::{quote_spanned, ToTokens}; use syn::{parse::Parse, spanned::Spanned, Result}; -use crate::common::*; +use crate::{derive_flag::DeriveFlag, newtype::Newtype}; /// A function on the wrapped type either wrapping an existing function or providing /// additional functionality -pub(crate) trait WrapperFunction: Parse + ToTokens {} +pub trait WrapperFunction: Parse + ToTokens {} /// script-side API Implementation generator for a particular script language. /// Helps avoid alot of boilerplate -pub(crate) trait WrapperImplementor: 'static { +pub trait WrapperImplementor: 'static { type Function: WrapperFunction; fn module_name() -> &'static str; @@ -36,15 +36,15 @@ pub(crate) trait WrapperImplementor: 'static { fn generate_newtype_functions(&mut self, new_type: &Newtype) -> Result>; /// Turns newtype list into fully implemented wrapper types - fn generate(&mut self, new_type: &Newtype) -> Result { - let definition = self.generate_newtype_definition(new_type)?; + fn generate(&mut self, new_type: Newtype) -> Result { + let definition = self.generate_newtype_definition(&new_type)?; let mut functions = - self.generate_derive_flag_functions(new_type, new_type.args.flags.iter())?; + self.generate_derive_flag_functions(&new_type, new_type.args.flags.iter())?; - functions.extend(self.generate_newtype_functions(new_type)?); + functions.extend(self.generate_newtype_functions(&new_type)?); - let implementation = self.generate_newtype_implementation(new_type, functions.iter())?; + let implementation = self.generate_newtype_implementation(&new_type, functions.iter())?; Ok(quote_spanned! {new_type.span()=> #definition diff --git a/bevy_mod_scripting_common/src/lib.rs b/bevy_mod_scripting_common/src/lib.rs new file mode 100644 index 0000000000..4d0e94ce6e --- /dev/null +++ b/bevy_mod_scripting_common/src/lib.rs @@ -0,0 +1,6 @@ +pub mod arg; +pub mod derive_flag; +pub mod implementor; +pub mod newtype; +pub mod ops; +pub mod utils; diff --git a/bevy_mod_scripting_derive/src/common/newtype.rs b/bevy_mod_scripting_common/src/newtype.rs similarity index 83% rename from bevy_mod_scripting_derive/src/common/newtype.rs rename to bevy_mod_scripting_common/src/newtype.rs index 2eef491f99..67f41021a1 100644 --- a/bevy_mod_scripting_derive/src/common/newtype.rs +++ b/bevy_mod_scripting_common/src/newtype.rs @@ -11,12 +11,10 @@ use syn::{ Attribute, Ident, Token, TypePath, }; -use crate::{lua_method::LuaMethod, DeriveFlag}; +use crate::{derive_flag::DeriveFlag, utils::EmptyToken}; use quote::ToTokens; -use super::WrapperFunction; - -pub(crate) struct NewtypeArgs { +pub struct NewtypeArgs { pub docstring: Vec, pub base_type: TypePath, pub type_colon: Token![:], @@ -73,7 +71,7 @@ impl NewtypeArgs { } seen_identifiers.insert(n); } - syn::Member::Unnamed(u) => {} + syn::Member::Unnamed(_) => {} } } } @@ -86,9 +84,6 @@ impl ToTokens for NewtypeArgs { fn to_tokens(&self, tokens: &mut TokenStream) { let docstrings = self.docstring.iter(); let base_type = &self.base_type; - let colon = (!self.flags.is_empty()) - .then(|| quote::quote! {:}) - .unwrap_or_default(); let flags = self.flags.iter(); tokens.extend(quote::quote! { #(#docstrings)* @@ -125,17 +120,19 @@ impl Parse for NewtypeArgs { } } -pub(crate) struct WrapperFunctionList { +pub struct WrapperFunctionList { + pub label: Ident, pub impl_: Token![impl], pub braces: Brace, - pub functions: Punctuated, + pub functions: TokenStream, } -impl ToTokens for WrapperFunctionList { +impl ToTokens for WrapperFunctionList { fn to_tokens(&self, tokens: &mut TokenStream) { + let ident = &self.label; let functions = &self.functions; tokens.extend(quote::quote! { - impl { + #ident impl { #functions } }) @@ -143,26 +140,27 @@ impl ToTokens for WrapperFunctionList { } #[allow(clippy::eval_order_dependence)] -impl Parse for WrapperFunctionList { +impl Parse for WrapperFunctionList { fn parse(input: ParseStream) -> Result { let f; Ok(Self { + label: input.parse()?, impl_: input.parse()?, braces: braced!(f in input), - functions: f.parse_terminated(T::parse)?, + functions: f.parse()?, }) } } -pub(crate) struct Newtype { +pub struct Newtype { pub args: NewtypeArgs, - pub additional_lua_functions: Option>, + pub impl_blocks: Punctuated, } impl ToTokens for Newtype { fn to_tokens(&self, tokens: &mut TokenStream) { let args = &self.args; - let functions = &self.additional_lua_functions; + let functions = &self.impl_blocks; tokens.extend(quote::quote!( {#args #functions} )) @@ -173,11 +171,7 @@ impl Parse for Newtype { fn parse(input: ParseStream) -> Result { Ok(Self { args: input.parse()?, - additional_lua_functions: if input.peek(Token![impl]) && !input.peek2(Token![fn]) { - Some(input.parse()?) - } else { - None - }, + impl_blocks: Punctuated::parse_terminated(input)?, }) } } diff --git a/bevy_mod_scripting_derive/src/common/ops.rs b/bevy_mod_scripting_common/src/ops.rs similarity index 97% rename from bevy_mod_scripting_derive/src/common/ops.rs rename to bevy_mod_scripting_common/src/ops.rs index 2985480077..5e9b594ea9 100644 --- a/bevy_mod_scripting_derive/src/common/ops.rs +++ b/bevy_mod_scripting_common/src/ops.rs @@ -5,11 +5,13 @@ use syn::{ Token, }; -use super::{arg::ArgType, impl_parse_enum}; +use crate::utils::impl_parse_enum; + +use super::arg::ArgType; impl_parse_enum!(input,ident: #[derive(PartialEq,Eq,Hash,Clone,Debug)] -pub(crate) enum OpName { +pub enum OpName { Add => {Ok(Self::Add{ident})}, Sub => {Ok(Self::Sub{ident})}, Mul => {Ok(Self::Mul{ident})}, @@ -48,7 +50,7 @@ impl MathOpName { /// Left or Right #[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) enum Side { +pub enum Side { Left, Right, } @@ -74,7 +76,7 @@ impl Side { /// Represents either a unary or binary expression, where at least one side has the receiver (self) type #[derive(PartialEq, Eq, Hash, Debug)] -pub(crate) struct OpExpr { +pub struct OpExpr { pub left: Option, pub op: OpName, pub right: ArgType, diff --git a/bevy_mod_scripting_derive/src/common/utils.rs b/bevy_mod_scripting_common/src/utils.rs similarity index 91% rename from bevy_mod_scripting_derive/src/common/utils.rs rename to bevy_mod_scripting_common/src/utils.rs index bfe3ab9d89..d4fc510bda 100644 --- a/bevy_mod_scripting_derive/src/common/utils.rs +++ b/bevy_mod_scripting_common/src/utils.rs @@ -61,6 +61,7 @@ macro_rules! impl_parse_enum { } } + #[allow(unused_variables)] impl $name { paste::paste!{ $($($other_impls)*)? @@ -98,7 +99,10 @@ macro_rules! impl_parse_enum { pub(crate) use impl_parse_enum; use proc_macro2::TokenStream; use quote::ToTokens; -use syn::{Attribute, Type}; +use syn::{ + parse::{Parse, ParseStream}, + Attribute, Type, +}; pub fn attribute_to_string_lit(attrs: &Attribute) -> TokenStream { attrs.tokens.clone().into_iter().skip(1).collect() @@ -122,3 +126,15 @@ pub fn type_base_string(t: &Type) -> Option { _ => None, } } + +#[derive(Default, Debug, Clone)] +pub struct EmptyToken; + +impl Parse for EmptyToken { + fn parse(_: ParseStream) -> Result { + Ok(Self) + } +} +impl ToTokens for EmptyToken { + fn to_tokens(&self, _: &mut TokenStream) {} +} diff --git a/bevy_mod_scripting_core/Cargo.toml b/bevy_mod_scripting_core/Cargo.toml new file mode 100644 index 0000000000..ad8d90a541 --- /dev/null +++ b/bevy_mod_scripting_core/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "bevy_mod_scripting_core" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Core traits and structures required for other parts of bevy_mod_scripting" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "lua"] +categories = ["game-development"] +readme = "readme.md" + +[lib] +name = "bevy_mod_scripting_core" +path = "src/lib.rs" + +# [package.metadata.docs.rs] +# features = [] + +# [package.metadata.release] +# enable-features=[] + +[features] + +# if enabled enables documentation updating in optimized builds +doc_always = [] + + +[dependencies] +bevy = { version = "0.8.0", default-features = false, features=["bevy_asset","bevy_gltf","bevy_animation","bevy_core_pipeline","bevy_ui","bevy_pbr","bevy_render","bevy_text","bevy_sprite","filesystem_watcher"]} +bevy_event_priority = {path = "../bevy_event_priority", version = "0.1.1"} +thiserror = "1.0.31" +paste = "1.0.7" + + + diff --git a/bevy_mod_scripting_core/readme.md b/bevy_mod_scripting_core/readme.md new file mode 100644 index 0000000000..8ab67ce5a9 --- /dev/null +++ b/bevy_mod_scripting_core/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_core + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_mod_scripting_core/src/asset.rs b/bevy_mod_scripting_core/src/asset.rs new file mode 100644 index 0000000000..1dc86bb292 --- /dev/null +++ b/bevy_mod_scripting_core/src/asset.rs @@ -0,0 +1,8 @@ +use bevy::asset::Asset; + +/// All code assets share this common interface. +/// When adding a new code asset don't forget to implement asset loading +/// and inserting appropriate systems when registering with the app +pub trait CodeAsset: Asset { + fn bytes(&self) -> &[u8]; +} diff --git a/src/hosts/docs.rs b/bevy_mod_scripting_core/src/docs.rs similarity index 85% rename from src/hosts/docs.rs rename to bevy_mod_scripting_core/src/docs.rs index 7c15f20837..4460a8c345 100644 --- a/src/hosts/docs.rs +++ b/bevy_mod_scripting_core/src/docs.rs @@ -1,4 +1,4 @@ -use crate::ScriptError; +use crate::error::ScriptError; /// A documentation piece exported by an `APIProvider` pub trait DocFragment: 'static { diff --git a/bevy_mod_scripting_core/src/error.rs b/bevy_mod_scripting_core/src/error.rs new file mode 100644 index 0000000000..f5a0f23657 --- /dev/null +++ b/bevy_mod_scripting_core/src/error.rs @@ -0,0 +1,30 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ScriptError { + #[error("Runtime error in script `{script}` {msg}")] + RuntimeError { script: String, msg: String }, + #[error("Failed to load script asset for `{script}`")] + FailedToLoad { script: String }, + #[error("Syntax error for script `{script}` {msg}")] + SyntaxError { script: String, msg: String }, + #[error("Callback method `{callback}` invalid for script `{script}` {msg}")] + InvalidCallback { + script: String, + callback: String, + msg: String, + }, + #[error("Failed to attach API for script `{script}` {msg}")] + FailedToAttachAPI { script: String, msg: String }, + #[error("Failed to generate documentation `{0}`")] + DocGenError(String), + #[error("{0}")] + Other(String), +} + +impl ScriptError { + /// Create new `ScriptError::Other` from another error + pub fn new_other(other: T) -> Self { + Self::Other(other.to_string()) + } +} diff --git a/src/hosts/mod.rs b/bevy_mod_scripting_core/src/hosts.rs similarity index 63% rename from src/hosts/mod.rs rename to bevy_mod_scripting_core/src/hosts.rs index 974e04a528..33922dfead 100644 --- a/src/hosts/mod.rs +++ b/bevy_mod_scripting_core/src/hosts.rs @@ -1,19 +1,11 @@ //! All script host related stuff - -pub mod docs; -pub mod mlua_host; -pub mod rhai_host; - -use bevy::{asset::Asset, ecs::system::SystemState, prelude::*, reflect::FromReflect}; -use bevy_event_priority::PriorityEventReader; -pub use {crate::docs::*, crate::mlua_host::*, crate::rhai_host::*}; - +use bevy::{asset::Asset, prelude::*, reflect::FromReflect}; use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, sync::atomic::{AtomicU32, Ordering}, }; -use crate::{ScriptError, ScriptErrorEvent}; +use crate::{asset::CodeAsset, docs::DocFragment, error::ScriptError}; /// Describes the target set of scripts this event should /// be handled by @@ -125,13 +117,6 @@ pub trait ScriptHost: Send + Sync + 'static + Default { fn register_with_app(app: &mut App, stage: impl StageLabel); } -/// All code assets share this common interface. -/// When adding a new code asset don't forget to implement asset loading -/// and inserting appropriate systems when registering with the app -pub trait CodeAsset: Asset { - fn bytes(&self) -> &[u8]; -} - /// Implementors can modify a script context in order to enable /// API access. ScriptHosts call `attach_api` when creating scripts pub trait APIProvider: 'static + Send + Sync { @@ -400,181 +385,3 @@ impl Default for ScriptCollection { } } } - -/// system state for exclusive systems dealing with script events -pub(crate) struct CachedScriptEventState<'w, 's, H: ScriptHost> { - event_state: SystemState<( - PriorityEventReader<'w, 's, H::ScriptEvent>, - EventWriter<'w, 's, ScriptErrorEvent>, - )>, -} - -impl<'w, 's, H: ScriptHost> FromWorld for CachedScriptEventState<'w, 's, H> { - fn from_world(world: &mut World) -> Self { - Self { - event_state: SystemState::new(world), - } - } -} - -/// Handles creating contexts for new/modified scripts -/// Scripts are likely not loaded instantly at this point, so most of the time -/// this system simply inserts an empty context -pub(crate) fn script_add_synchronizer( - query: Query< - ( - Entity, - &ScriptCollection, - ChangeTrackers>, - ), - Changed>, - >, - mut host: ResMut, - mut providers: ResMut>, - script_assets: Res>, - mut contexts: ResMut>, -) { - debug!("Handling addition/modification of scripts"); - - query.for_each(|(entity, new_scripts, tracker)| { - if tracker.is_added() { - new_scripts.scripts.iter().for_each(|new_script| { - Script::::insert_new_script_context::( - &mut host, - new_script, - entity, - &script_assets, - &mut providers, - &mut contexts, - ) - }) - } else { - // changed but structure already exists in contexts - // find out what's changed - // we only care about added or removed scripts here - // if the script asset gets changed we deal with that elsewhere - - let context_ids = contexts - .context_entities - .iter() - .filter_map(|(sid, (e, _, _))| if *e == entity { Some(sid) } else { None }) - .cloned() - .collect::>(); - let script_ids = new_scripts - .scripts - .iter() - .map(|s| s.id()) - .collect::>(); - - let removed_scripts = context_ids.difference(&script_ids); - let added_scripts = script_ids.difference(&context_ids); - - for r in removed_scripts { - contexts.remove_context(*r); - } - - for a in added_scripts { - let script = new_scripts.scripts.iter().find(|e| &e.id == a).unwrap(); - Script::::insert_new_script_context::( - &mut host, - script, - entity, - &script_assets, - &mut providers, - &mut contexts, - ) - } - } - }) -} - -/// Handles the removal of script components and their contexts -pub(crate) fn script_remove_synchronizer( - query: RemovedComponents>, - mut contexts: ResMut>, -) { - query.iter().for_each(|v| { - // we know that this entity used to have a script component - // ergo a script context must exist in ctxts, remove all scripts on the entity - contexts.remove_context(v.id()); - }) -} - -/// Reloads hot-reloaded scripts, or loads missing contexts for scripts which were added but not loaded -pub(crate) fn script_hot_reload_handler( - mut events: EventReader>, - mut host: ResMut, - scripts: Query<&ScriptCollection>, - script_assets: Res>, - mut providers: ResMut>, - mut contexts: ResMut>, -) { - for e in events.iter() { - let (handle, created) = match e { - AssetEvent::Modified { handle } => (handle, false), - AssetEvent::Created { handle } => (handle, true), - _ => continue, - }; - - // find script using this handle by handle id - // whether this script was modified or created - // if a script exists with this handle, we should reload it to load in a new context - // which at this point will be either None or Some(outdated context) - // both ways are fine - for scripts in scripts.iter() { - for script in &scripts.scripts { - // the script could have well loaded in the same frame that it was added - // in that case it will have a context attached and we do not want to reload it - if &script.handle == handle && !(contexts.has_context(script.id()) && created) { - Script::::reload_script::( - &mut host, - script, - &script_assets, - &mut providers, - &mut contexts, - ); - } - } - } - } -} - -/// Lets the script host handle all script events -pub(crate) fn script_event_handler( - world: &mut World, -) { - // we need to collect the events to drop the borrow of the world - let events = world.resource_scope(|world, mut cached_state: Mut>| { - let (mut cached_state, _) = cached_state.event_state.get_mut(world); - cached_state - .iter_prio_range(MAX, MIN) - .collect::>() - }); - - // we need a resource scope to be able to simultaneously access the contexts as well - // as provide world access to scripts - // afaik there is not really a better way to do this in bevy just now - world.resource_scope(|world, mut ctxts: Mut>| { - let ctx_iter = - ctxts - .as_mut() - .context_entities - .iter_mut() - .filter_map(|(sid, (entity, o, name))| { - let ctx = match o { - Some(v) => v, - None => return None, - }; - - Some(( - ScriptData { - sid: *sid, - entity: *entity, - name, - }, - ctx, - )) - }); - world.resource_scope(|world, host: Mut| host.handle_events(world, &events, ctx_iter)); - }); -} diff --git a/bevy_mod_scripting_core/src/lib.rs b/bevy_mod_scripting_core/src/lib.rs new file mode 100644 index 0000000000..8ef2d4c9f9 --- /dev/null +++ b/bevy_mod_scripting_core/src/lib.rs @@ -0,0 +1,198 @@ +use crate::{ + error::ScriptError, + hosts::{APIProvider, APIProviders, ScriptHost}, +}; +use bevy::{ecs::schedule::IntoRunCriteria, prelude::*}; +use systems::script_event_handler; + +pub mod asset; +pub mod docs; +pub mod error; +pub mod hosts; +pub mod systems; +pub mod prelude { + // general + pub use { + crate::asset::CodeAsset, + crate::docs::DocFragment, + crate::error::ScriptError, + crate::hosts::{ + APIProvider, APIProviders, Recipients, Script, ScriptCollection, ScriptContexts, + ScriptData, ScriptEvent, ScriptHost, + }, + crate::{ + AddScriptApiProvider, AddScriptHost, AddScriptHostHandler, GenDocumentation, + ScriptErrorEvent, ScriptingPlugin, + }, + bevy_event_priority::{ + AddPriorityEvent, PriorityEvent, PriorityEventReader, PriorityEventWriter, + PriorityEvents, PriorityIterator, + }, + }; +} +pub use bevy_event_priority as events; + +#[derive(Default)] +/// Bevy plugin enabling run-time scripting +pub struct ScriptingPlugin; + +impl Plugin for ScriptingPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.add_event::(); + } +} + +/// An error coming from a script +#[derive(Debug)] +pub struct ScriptErrorEvent { + pub err: ScriptError, +} + +pub trait GenDocumentation { + fn update_documentation(&mut self) -> &mut Self; +} + +impl GenDocumentation for App { + /// Updates/Generates documentation and any other artifacts required for script API's. Disabled in optimized builds unless `doc_always` feature is enabled. + fn update_documentation(&mut self) -> &mut Self { + #[cfg(any(debug_assertions, feature = "doc_always"))] + { + info!("Generating documentation"); + let w = &mut self.world; + let providers: &APIProviders = w.resource(); + if let Err(e) = providers.gen_all() { + error!("{}", e); + } + info!("Documentation generated"); + } + + self + } +} + +/// Trait for app builder notation +pub trait AddScriptHost { + /// registers the given script host with your app + fn add_script_host(&mut self, stage: S) -> &mut Self; +} + +impl AddScriptHost for App { + fn add_script_host(&mut self, stage: S) -> &mut Self { + T::register_with_app(self, stage); + self.init_resource::(); + self + } +} + +pub trait AddScriptApiProvider { + fn add_api_provider( + &mut self, + provider: Box< + dyn APIProvider< + APITarget = T::APITarget, + DocTarget = T::DocTarget, + ScriptContext = T::ScriptContext, + >, + >, + ) -> &mut Self; +} + +impl AddScriptApiProvider for App { + fn add_api_provider( + &mut self, + provider: Box< + dyn APIProvider< + APITarget = T::APITarget, + DocTarget = T::DocTarget, + ScriptContext = T::ScriptContext, + >, + >, + ) -> &mut Self { + provider.register_with_app(self); + let w = &mut self.world; + let providers: &mut APIProviders = &mut w.resource_mut(); + providers.providers.push(provider); + self + } +} + +pub trait AddScriptHostHandler { + /// Enables this script host to handle events with priorities in the range [0,min_prio] (inclusive), + /// during the runtime of the given stage. + /// + /// Think of handler stages as a way to run certain types of events at various points in your engine. + /// A good example of this is Unity [game loop's](https://docs.unity3d.com/Manual/ExecutionOrder.html) `onUpdate` and `onFixedUpdate`. + /// FixedUpdate runs *before* any physics while Update runs after physics and input events. + /// + /// A similar setup can be achieved by using a separate stage before and after your physics, + /// then assigning event priorities such that your events are forced to run at a particular stage, for example: + /// + /// PrePhysics: min_prio = 1 + /// PostPhysics: min_prio = 4 + /// + /// | Priority | Handler | Event | + /// | -------- | ----------- | ------------ | + /// | 0 | PrePhysics | Start | + /// | 1 | PrePhysics | FixedUpdate | + /// | 2 | PostPhysics | OnCollision | + /// | 3 | PostPhysics | OnMouse | + /// | 4 | PostPhysics | Update | + /// + /// The *frequency* of running these events, is controlled by your systems, if the event is not emitted, it cannot not handled. + /// Of course there is nothing stopping your from emitting a single event type at varying priorities. + fn add_script_handler_stage( + &mut self, + stage: S, + ) -> &mut Self; + + /// Like `add_script_handler_stage` but with additional run criteria + fn add_script_handler_stage_with_criteria< + T: ScriptHost, + S: StageLabel, + M, + C: IntoRunCriteria, + const MAX: u32, + const MIN: u32, + >( + &mut self, + stage: S, + criteria: C, + ) -> &mut Self; +} + +impl AddScriptHostHandler for App { + fn add_script_handler_stage( + &mut self, + stage: S, + ) -> &mut Self { + self.add_system_to_stage( + stage, + script_event_handler:: + .exclusive_system() + .at_end(), + ); + self + } + + fn add_script_handler_stage_with_criteria< + T: ScriptHost, + S: StageLabel, + M, + C: IntoRunCriteria, + const MAX: u32, + const MIN: u32, + >( + &mut self, + stage: S, + criteria: C, + ) -> &mut Self { + self.add_system_to_stage( + stage, + script_event_handler:: + .exclusive_system() + .at_end() + .with_run_criteria(criteria), + ); + self + } +} diff --git a/bevy_mod_scripting_core/src/systems.rs b/bevy_mod_scripting_core/src/systems.rs new file mode 100644 index 0000000000..20c954a2d0 --- /dev/null +++ b/bevy_mod_scripting_core/src/systems.rs @@ -0,0 +1,191 @@ +use std::collections::HashSet; + +use bevy::{ + ecs::system::SystemState, + prelude::{ + debug, AssetEvent, Assets, ChangeTrackers, Changed, Entity, EventReader, EventWriter, + FromWorld, Mut, Query, RemovedComponents, Res, ResMut, World, + }, +}; +use bevy_event_priority::PriorityEventReader; + +use crate::{ + prelude::{APIProviders, Script, ScriptCollection, ScriptContexts, ScriptData, ScriptHost}, + ScriptErrorEvent, +}; + +/// Handles creating contexts for new/modified scripts +/// Scripts are likely not loaded instantly at this point, so most of the time +/// this system simply inserts an empty context +pub fn script_add_synchronizer( + query: Query< + ( + Entity, + &ScriptCollection, + ChangeTrackers>, + ), + Changed>, + >, + mut host: ResMut, + mut providers: ResMut>, + script_assets: Res>, + mut contexts: ResMut>, +) { + debug!("Handling addition/modification of scripts"); + + query.for_each(|(entity, new_scripts, tracker)| { + if tracker.is_added() { + new_scripts.scripts.iter().for_each(|new_script| { + Script::::insert_new_script_context::( + &mut host, + new_script, + entity, + &script_assets, + &mut providers, + &mut contexts, + ) + }) + } else { + // changed but structure already exists in contexts + // find out what's changed + // we only care about added or removed scripts here + // if the script asset gets changed we deal with that elsewhere + + let context_ids = contexts + .context_entities + .iter() + .filter_map(|(sid, (e, _, _))| if *e == entity { Some(sid) } else { None }) + .cloned() + .collect::>(); + let script_ids = new_scripts + .scripts + .iter() + .map(|s| s.id()) + .collect::>(); + + let removed_scripts = context_ids.difference(&script_ids); + let added_scripts = script_ids.difference(&context_ids); + + for r in removed_scripts { + contexts.remove_context(*r); + } + + for a in added_scripts { + let script = new_scripts.scripts.iter().find(|e| &e.id() == a).unwrap(); + Script::::insert_new_script_context::( + &mut host, + script, + entity, + &script_assets, + &mut providers, + &mut contexts, + ) + } + } + }) +} + +/// Handles the removal of script components and their contexts +pub fn script_remove_synchronizer( + query: RemovedComponents>, + mut contexts: ResMut>, +) { + query.iter().for_each(|v| { + // we know that this entity used to have a script component + // ergo a script context must exist in ctxts, remove all scripts on the entity + contexts.remove_context(v.id()); + }) +} + +/// Reloads hot-reloaded scripts, or loads missing contexts for scripts which were added but not loaded +pub fn script_hot_reload_handler( + mut events: EventReader>, + mut host: ResMut, + scripts: Query<&ScriptCollection>, + script_assets: Res>, + mut providers: ResMut>, + mut contexts: ResMut>, +) { + for e in events.iter() { + let (handle, created) = match e { + AssetEvent::Modified { handle } => (handle, false), + AssetEvent::Created { handle } => (handle, true), + _ => continue, + }; + + // find script using this handle by handle id + // whether this script was modified or created + // if a script exists with this handle, we should reload it to load in a new context + // which at this point will be either None or Some(outdated context) + // both ways are fine + for scripts in scripts.iter() { + for script in &scripts.scripts { + // the script could have well loaded in the same frame that it was added + // in that case it will have a context attached and we do not want to reload it + if script.handle() == handle && !(contexts.has_context(script.id()) && created) { + Script::::reload_script::( + &mut host, + script, + &script_assets, + &mut providers, + &mut contexts, + ); + } + } + } + } +} + +/// Lets the script host handle all script events +pub fn script_event_handler(world: &mut World) { + // we need to collect the events to drop the borrow of the world + let events = world.resource_scope(|world, mut cached_state: Mut>| { + let (mut cached_state, _) = cached_state.event_state.get_mut(world); + cached_state + .iter_prio_range(MAX, MIN) + .collect::>() + }); + + // we need a resource scope to be able to simultaneously access the contexts as well + // as provide world access to scripts + // afaik there is not really a better way to do this in bevy just now + world.resource_scope(|world, mut ctxts: Mut>| { + let ctx_iter = + ctxts + .as_mut() + .context_entities + .iter_mut() + .filter_map(|(sid, (entity, o, name))| { + let ctx = match o { + Some(v) => v, + None => return None, + }; + + Some(( + ScriptData { + sid: *sid, + entity: *entity, + name, + }, + ctx, + )) + }); + world.resource_scope(|world, host: Mut| host.handle_events(world, &events, ctx_iter)); + }); +} + +/// system state for exclusive systems dealing with script events +pub struct CachedScriptEventState<'w, 's, H: ScriptHost> { + pub event_state: SystemState<( + PriorityEventReader<'w, 's, H::ScriptEvent>, + EventWriter<'w, 's, ScriptErrorEvent>, + )>, +} + +impl<'w, 's, H: ScriptHost> FromWorld for CachedScriptEventState<'w, 's, H> { + fn from_world(world: &mut World) -> Self { + Self { + event_state: SystemState::new(world), + } + } +} diff --git a/bevy_mod_scripting_derive/Cargo.toml b/bevy_mod_scripting_derive/Cargo.toml index 4cf4fe6761..e909270683 100644 --- a/bevy_mod_scripting_derive/Cargo.toml +++ b/bevy_mod_scripting_derive/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/makspll/bevy_mod_scripting" homepage = "https://github.com/makspll/bevy_mod_scripting" keywords = ["bevy", "gamedev", "scripting", "lua"] categories = ["game-development"] -readme = "../readme.md" +readme = "readme.md" [lib] name = "bevy_mod_scripting_derive" @@ -18,6 +18,7 @@ path = "src/lib.rs" [dependencies] +bevy_mod_scripting_common = {path = "../bevy_mod_scripting_common", version = "0.1.1"} paste = "1.0.7" syn = {version="1.0.57",features=["full","fold","extra-traits"]} quote = "1.0.8" diff --git a/bevy_mod_scripting_derive/readme.md b/bevy_mod_scripting_derive/readme.md new file mode 100644 index 0000000000..5bfd0c9f4d --- /dev/null +++ b/bevy_mod_scripting_derive/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_derive + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_mod_scripting_derive/src/common/mod.rs b/bevy_mod_scripting_derive/src/common/mod.rs deleted file mode 100644 index af5bc5334e..0000000000 --- a/bevy_mod_scripting_derive/src/common/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub(crate) mod arg; -pub(crate) mod derive_flag; -pub(crate) mod implementor; -pub(crate) mod newtype; -pub(crate) mod ops; -pub(crate) mod utils; - -pub(crate) use {derive_flag::*, implementor::*, newtype::*, utils::*}; diff --git a/bevy_mod_scripting_derive/src/lib.rs b/bevy_mod_scripting_derive/src/lib.rs index de1246617c..745d7363a8 100644 --- a/bevy_mod_scripting_derive/src/lib.rs +++ b/bevy_mod_scripting_derive/src/lib.rs @@ -1,91 +1,8 @@ #![allow(dead_code, unused_variables, unused_features)] - -pub(crate) mod common; -pub(crate) mod lua; - use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens}; -use syn::{ - braced, bracketed, parenthesized, - parse::{Parse, ParseStream}, - parse_macro_input, - punctuated::Punctuated, - token::{Brace, Bracket, Paren}, - ItemFn, Result, Token, Type, -}; - -pub(crate) use {common::*, lua::*}; - -#[derive(Default, Debug, Clone)] -struct EmptyToken; - -impl Parse for EmptyToken { - fn parse(input: ParseStream) -> Result { - Ok(Self) - } -} -impl ToTokens for EmptyToken { - fn to_tokens(&self, tokens: &mut TokenStream2) {} -} - -struct NewtypeList { - paren: Paren, - module_headers: TokenStream2, - sq_bracket1: Bracket, - additional_types: Punctuated, - sq_bracket2: Bracket, - new_types: Punctuated, -} -#[allow(clippy::eval_order_dependence)] -impl Parse for NewtypeList { - fn parse(input: ParseStream) -> Result { - let h; - let f; - let g; - Ok(Self { - paren: parenthesized!(h in input), - module_headers: h.parse()?, - sq_bracket1: bracketed!(f in input), - additional_types: f.parse_terminated(Type::parse)?, - sq_bracket2: bracketed!(g in input), - new_types: g.parse_terminated(Newtype::parse)?, - }) - } -} -impl ToTokens for NewtypeList { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let module_headers = &self.module_headers; - let external_types = &self.additional_types; - let types = &self.new_types; - tokens.extend(quote! { - (#module_headers) - [#external_types] - [#types] - }) - } -} - -struct AdditionalImplBlock { - impl_token: Token![impl], - fn_token: Token![fn], - impl_braces: Brace, - functions: Punctuated, -} - -#[allow(clippy::eval_order_dependence)] -impl Parse for AdditionalImplBlock { - fn parse(input: ParseStream) -> Result { - let f; - Ok(Self { - impl_token: input.parse()?, - fn_token: input.parse()?, - impl_braces: braced!(f in input), - functions: f.parse_terminated(ItemFn::parse)?, - }) - } -} +use quote::{format_ident, quote_spanned, ToTokens}; +use syn::{parse::Parse, parse_macro_input, spanned::Spanned, Attribute}; /// A convenience macro which derives a lotta things to make your type work in all supported/enabled scripting languages, and provide static typing where possible. /// @@ -128,6 +45,7 @@ impl Parse for AdditionalImplBlock { /// } /// } /// impl_script_newtype!( +/// #[languages(lua,rhai)] /// MyStruct: /// Fields( /// my_field: Raw(bool) @@ -141,12 +59,103 @@ impl Parse for AdditionalImplBlock { /// ``` #[proc_macro] pub fn impl_script_newtype(input: TokenStream) -> TokenStream { - let new_type = parse_macro_input!(input as Newtype); + let invocation = parse_macro_input!(input as MacroInvocation); + let mut output: proc_macro2::TokenStream = Default::default(); + // find the language implementor macro id's + match invocation.languages.parse_meta() { + Ok(syn::Meta::List(list)) => { + if !list.path.is_ident("languages") { + return syn::Error::new_spanned(list, "Expected `langauges(..)` meta list") + .to_compile_error() + .into(); + } + + // now create an invocation per language specified + for language in &list.nested { + let mut feature_gate = false; + let mut inner_language = None; + if let syn::NestedMeta::Meta(syn::Meta::List(sub_list)) = language { + if sub_list.path.is_ident("on_feature") { + if let Some(syn::NestedMeta::Meta(syn::Meta::Path(path))) = + sub_list.nested.first() + { + if let Some(ident) = path.get_ident() { + inner_language = Some(ident); + feature_gate = true; + } + } + } + } else if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = language { + if let Some(ident) = path.get_ident() { + inner_language = Some(ident) + } + } + + let inner_language = + match inner_language { + Some(v) => v, + None => return syn::Error::new_spanned( + language, + "Expected `on_feature(x)` or `x` attribute where x is a valid language", + ) + .to_compile_error() + .into(), + }; + + let lang_str = inner_language.to_string(); + let macro_ident = format_ident!("impl_{}_newtype", inner_language); + let inner = invocation.inner.clone(); + let feature_gate = feature_gate.then_some(quote::quote!(#[cfg(feature=#lang_str)])); + output.extend(quote_spanned! {language.span()=> + #feature_gate + #macro_ident!{ + #inner + } + }); + } + } + _ => { + return syn::Error::new( + invocation.span(), + "Expected attribute of the form #[languages(..)]", + ) + .to_compile_error() + .into() + } + }; - let mut lua = LuaImplementor::default(); + output.into() +} + +pub(crate) struct MacroInvocation { + pub languages: Attribute, + pub inner: proc_macro2::TokenStream, +} + +impl Parse for MacroInvocation { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self { + languages: Attribute::parse_outer(input)? + .into_iter() + .next() + .ok_or_else(|| { + syn::Error::new( + input.span(), + "Expected meta attribute selecting language implementors", + ) + })?, + inner: input.parse()?, + }) + } +} - match lua.generate(&new_type) { - Ok(v) => v.into(), - Err(e) => e.into_compile_error().into(), +impl ToTokens for MacroInvocation { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let languages = &self.languages; + let inner = &self.inner; + tokens.extend(quote::quote! { + #languages + #inner + }); } } diff --git a/bevy_script_api/Cargo.toml b/bevy_script_api/Cargo.toml new file mode 100644 index 0000000000..3bcaf3086a --- /dev/null +++ b/bevy_script_api/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "bevy_script_api" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Bevy API for multiple script languages, part of bevy_mod_scripting." +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "lua","rhai"] +categories = ["game-development"] +readme = "readme.md" + +[features] +lua = ["bevy_mod_scripting_lua","bevy_mod_scripting_lua_derive"] +rhai = ["bevy_mod_scripting_rhai"] + +[dependencies] +bevy = { version = "0.8.0", default-features = false, features=["bevy_asset","bevy_gltf","bevy_animation","bevy_core_pipeline","bevy_ui","bevy_pbr","bevy_render","bevy_text","bevy_sprite","filesystem_watcher"]} +bevy_mod_scripting_derive = { path="../bevy_mod_scripting_derive", version = "0.1.1"} +bevy_mod_scripting_core = { path="../bevy_mod_scripting_core", version = "0.1.1"} +parking_lot="0.12.1" +paste="1.0.7" +thiserror="1.0.32" +# lua +bevy_mod_scripting_lua={path="../languages/bevy_mod_scripting_lua", version="0.1.1", optional=true} +bevy_mod_scripting_lua_derive={path="../languages/bevy_mod_scripting_lua_derive", version="0.1.1", optional=true} +bevy_mod_scripting_rhai={path="../languages/bevy_mod_scripting_rhai", version="0.1.1", optional=true} diff --git a/bevy_script_api/readme.md b/bevy_script_api/readme.md new file mode 100644 index 0000000000..2a766e099a --- /dev/null +++ b/bevy_script_api/readme.md @@ -0,0 +1,3 @@ +# bevy_script_api + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_script_api/src/error.rs b/bevy_script_api/src/error.rs new file mode 100644 index 0000000000..180b597bf9 --- /dev/null +++ b/bevy_script_api/src/error.rs @@ -0,0 +1,27 @@ +use std::borrow::Cow; + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ReflectionError { + #[error("Base reference `{base}` is invalid. {reason}")] + InvalidBaseReference { base: String, reason: String }, + #[error("Insuficient provenance error while accessing `{path}`. {msg}")] + InsufficientProvenance { path: String, msg: String }, + #[error("Invalid reflection path: `{path}`. {msg}")] + InvalidReflectionPath { path: String, msg: String }, + #[error("Cannot downcast from `{from}` to `{to}`")] + CannotDowncast { + from: Cow<'static, str>, + to: Cow<'static, str>, + }, + #[error("{0}")] + Other(String), +} + +#[cfg(feature = "lua")] +impl From for bevy_mod_scripting_lua::tealr::mlu::mlua::Error { + fn from(e: ReflectionError) -> Self { + bevy_mod_scripting_lua::tealr::mlu::mlua::Error::RuntimeError(e.to_string()) + } +} diff --git a/src/api/generated.rs b/bevy_script_api/src/generated.rs similarity index 93% rename from src/api/generated.rs rename to bevy_script_api/src/generated.rs index 29710d886b..f621362553 100644 --- a/src/api/generated.rs +++ b/bevy_script_api/src/generated.rs @@ -1,15 +1,10 @@ -#[allow(clippy::all)] +#![allow(clippy::all, unused_imports)] // This file is generated by `bevy_mod_scripting_derive/main.rs` change the template not this file -extern crate self as bevy_mod_scripting; -use crate::impl_tealr_generic; +extern crate self as bevy_script_api; use crate::{ - api::ValueIndex, impl_tealr_any_union, APIProvider, LuaDocFragment, ReflectPathElem, - ReflectedValue, ReflectionError, RegisterForeignLuaType, -}; -use crate::{ - lua::bevy::{LuaScriptData, LuaTypeRegistration, LuaWorld}, - std::LuaVec, - DummyTypeName, + error::ReflectionError, + script_ref::{ReflectedValue, ValueIndex}, + sub_reflect::ReflectPathElem, }; use bevy::animation::AnimationPlayer; use bevy::asset::AssetPathId; @@ -129,14 +124,18 @@ use bevy::ui::Style; use bevy::ui::UiColor; use bevy::ui::UiImage; use bevy::ui::Val; +use bevy_mod_scripting_core::prelude::*; use bevy_mod_scripting_derive::impl_script_newtype; use std::ops::*; use std::sync::Mutex; -use tealr::mlu::{ - mlua, - mlua::{prelude::*, MetaMethod}, +#[cfg(feature = "lua")] +use { + crate::lua::RegisterForeignLuaType, + bevy_mod_scripting_lua::{docs::LuaDocFragment, tealr::mlu::mlua::MetaMethod}, + bevy_mod_scripting_lua_derive::impl_lua_newtype, }; impl_script_newtype! { + #[languages(on_feature(lua))] ///Defines how each line is aligned within the flexbox. /// ///It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items. @@ -155,11 +154,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///How items are aligned according to the cross axis bevy_ui::AlignItems : Clone + @@ -176,11 +176,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Works like [`AlignItems`] but applies only to a single item bevy_ui::AlignSelf : Clone + @@ -197,11 +198,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Defines the text direction /// ///For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left). @@ -220,11 +222,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Defines how flexbox items are ordered within a flexbox bevy_ui::FlexDirection : Clone + @@ -241,11 +244,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Defines if flexbox items appear on a single line or on multiple lines bevy_ui::FlexWrap : Clone + @@ -262,11 +266,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes whether the node should block interactions with lower nodes bevy_ui::FocusPolicy : Clone + @@ -283,11 +288,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes what type of input interaction has occurred for a UI node. /// ///This is commonly queried with a `Changed` filter. @@ -317,11 +323,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Defines how items are aligned according to the main axis bevy_ui::JustifyContent : Clone + @@ -338,11 +345,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Whether to show or hide overflowing items bevy_ui::Overflow : Clone + @@ -359,11 +367,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The strategy used to position this node bevy_ui::PositionType : Clone + @@ -380,11 +389,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An enum that describes possible types of value in flexbox layout options bevy_ui::Val : Clone + @@ -402,11 +412,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The calculated clip of the node bevy_ui::CalculatedClip : Clone + @@ -425,11 +436,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The calculated size of the node bevy_ui::CalculatedSize : Clone + @@ -448,11 +460,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes the size of a UI node bevy_ui::Node : Clone + @@ -471,11 +484,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes the style of a UI node /// ///It uses the [Flexbox](https://cssreference.io/flexbox/) system. @@ -542,11 +556,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The color of the node bevy_ui::UiColor : Clone + @@ -564,11 +579,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The image of the node bevy_ui::UiImage : Clone + @@ -586,11 +602,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Marker struct for buttons bevy_ui::widget::Button : Clone + @@ -607,11 +624,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes how to resize the Image node bevy_ui::widget::ImageMode : Clone + @@ -628,11 +646,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Whether to use a Flexbox layout model. /// ///Part of the [`Style`] component. @@ -651,11 +670,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Animation controls bevy_animation::AnimationPlayer : Methods @@ -685,11 +705,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Component used to identify an entity. Stores a hash for faster comparisons ///The hash is eagerly re-computed upon each update to the name. /// @@ -711,11 +732,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_gltf::GltfExtras : Clone + Debug + @@ -732,11 +754,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Contains references to the child entities of this entity bevy_hierarchy::Children : Debug + @@ -755,11 +778,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Holds a reference to the parent entity of this entity. ///This component should only be present on entities that actually have a parent entity. bevy_hierarchy::Parent : @@ -779,11 +803,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The maximum width and height of text. The text will wrap according to the specified size. ///Characters out of the bounds after wrapping will be truncated. Text is aligned according to the ///specified `TextAlignment`. @@ -807,11 +832,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The calculated size of text drawn in 2D scene. bevy_text::Text2dSize : Clone + @@ -829,11 +855,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_text::Text : Clone + Debug + @@ -854,11 +881,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_text::TextAlignment : Clone + Debug + @@ -876,11 +904,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_text::TextSection : Clone + Debug + @@ -901,11 +930,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_text::TextStyle : Clone + Debug + @@ -924,11 +954,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes horizontal alignment preference for positioning & bounds. bevy_text::HorizontalAlign : Clone + @@ -945,11 +976,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes vertical alignment preference for positioning & bounds. Currently a placeholder ///for future functionality. bevy_text::VerticalAlign : @@ -967,11 +999,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A Stopwatch is a struct that track elapsed time when started. /// ///# Examples @@ -1094,11 +1127,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Tracks elapsed time. Enters the finished state once `duration` is reached. /// ///Non repeating timers will stop tracking and stay in the finished state until reset. @@ -1292,11 +1326,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Lightweight identifier of an [entity](crate::entity). /// ///The identifier is implemented using a [generational index]: a combination of an ID and a generation. @@ -1437,11 +1472,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describe the position of an entity. If the entity has a parent, the position is relative ///to its parent position. /// @@ -1627,11 +1663,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describe the position of an entity relative to the reference frame. /// ///* To place or move an entity, you should set its [`Transform`]. @@ -1719,11 +1756,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An ambient light, which lights the entire scene equally. bevy_pbr::AmbientLight : Clone + @@ -1743,11 +1781,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_pbr::CubemapVisibleEntities : Clone + Debug + @@ -1763,11 +1802,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A Directional light. /// ///Directional lights don't exist in reality but they are a good @@ -1818,11 +1858,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_pbr::DirectionalLightShadowMap : Clone + Debug + @@ -1839,11 +1880,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not cast shadows. bevy_pbr::NotShadowCaster : Methods @@ -1858,11 +1900,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not receive shadows. bevy_pbr::NotShadowReceiver : Methods @@ -1877,11 +1920,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A light that emits light in all directions from a central point. /// ///Real-world values for `intensity` (luminous power in lumens) based on the electrical power @@ -1924,11 +1968,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_pbr::PointLightShadowMap : Clone + Debug + @@ -1945,11 +1990,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Alpha mode bevy_pbr::AlphaMode : Clone + @@ -1966,11 +2012,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled bevy_pbr::wireframe::Wireframe : Clone + @@ -1987,11 +2034,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_pbr::wireframe::WireframeConfig : Clone + Debug + @@ -2009,11 +2057,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The depth clear operation to perform for the main 3d pass. bevy_core_pipeline::core_3d::Camera3dDepthLoadOp : Clone + @@ -2030,11 +2079,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///When used as a resource, sets the color that is used to clear the screen between frames. /// ///This color appears as the "background" color for simple apps, when @@ -2055,11 +2105,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_core_pipeline::clear_color::ClearColorConfig : Clone + Debug + @@ -2075,11 +2126,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_core_pipeline::core_2d::Camera2d : Clone + Methods @@ -2095,11 +2147,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Configuration for the "main 3d render graph". bevy_core_pipeline::core_3d::Camera3d : Clone + @@ -2119,11 +2172,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///How a sprite is positioned relative to its [`Transform`](bevy_transform::components::Transform). ///It defaults to `Anchor::Center`. bevy_sprite::Anchor : @@ -2143,11 +2197,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Component for rendering with meshes in the 2d pipeline, usually with a [2d material](crate::Material2d) such as [`ColorMaterial`](crate::ColorMaterial). /// ///It wraps a [`Handle`] to differentiate from the 3d pipelines which use the handles directly as components @@ -2167,11 +2222,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_sprite::TextureAtlasSprite : Clone + Debug + @@ -2197,11 +2253,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_sprite::Sprite : Clone + Debug + @@ -2228,11 +2285,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere ///(top-left, bottom-left, etc) bevy_sprite::Rect : @@ -2260,11 +2318,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Describes which rendering layers an entity belongs to. /// ///Cameras with this component will only render entities with intersecting @@ -2307,11 +2366,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///User indication of whether an entity is visible. Propagates down the entity hierarchy. ///If an entity is hidden in this way, all [`Children`] (and all of their children and so on) will also be hidden. ///This is done by setting the values of their [`ComputedVisibility`] component. @@ -2337,11 +2397,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Collection of entities visible from the current view. /// ///This component contains all entities which are visible from the currently @@ -2373,11 +2434,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering bevy_render::view::visibility::ComputedVisibility : Clone + @@ -2424,11 +2486,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::mesh::skinning::SkinnedMesh : Clone + Debug + @@ -2446,11 +2509,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::ScalingMode : Clone + Debug + @@ -2466,11 +2530,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::WindowOrigin : Clone + Debug + @@ -2486,11 +2551,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::color::Color : Clone + Debug + @@ -2568,11 +2634,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An Axis-Aligned Bounding Box bevy_render::primitives::Aabb : Clone + @@ -2597,11 +2664,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::primitives::CubemapFrusta : Debug + Methods @@ -2616,11 +2684,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A frustum defined by the 6 containing planes ///Planes are ordered left, right, top, bottom, near, far ///Normals point into the contained volume @@ -2643,11 +2712,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing). /// ///# Example @@ -2680,11 +2750,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::Camera : Clone + Debug + @@ -2714,11 +2785,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///The "target" that a [`Camera`] will render to. For example, this could be a [`Window`](bevy_window::Window) ///swapchain or an [`Image`]. bevy_render::camera::RenderTarget : @@ -2736,11 +2808,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Render viewport configuration for the [`Camera`] component. /// ///The viewport defines the area on the render target to which the camera renders its image. @@ -2769,11 +2842,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A configurable [`CameraProjection`] that can select its projection type at runtime. bevy_render::camera::Projection : Clone + @@ -2798,11 +2872,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::OrthographicProjection : Clone + Debug + @@ -2838,11 +2913,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::PerspectiveProjection : Clone + Debug + @@ -2871,11 +2947,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] bevy_render::camera::DepthCalculation : Clone + Debug + @@ -2891,11 +2968,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Configures the [`RenderGraph`](crate::render_graph::RenderGraph) name assigned to be run for a given [`Camera`] entity. bevy_render::camera::CameraRenderGraph : Methods @@ -2910,11 +2988,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An unique identifier to an asset path. bevy_asset::AssetPathId : Clone + @@ -2937,11 +3016,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An unique identifier to a sub-asset label. bevy_asset::LabelId : Clone + @@ -2958,11 +3038,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///An unique identifier to the source path of an asset. bevy_asset::SourcePathId : Clone + @@ -2979,11 +3060,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A unique, stable asset id. bevy_asset::HandleId : Clone + @@ -3000,13 +3082,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2-dimensional vector. - glam::f32::vec2::Vec2 : + glam::f32::Vec2 : Clone + Debug + Methods @@ -3335,15 +3418,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional vector. - glam::f32::vec3::Vec3 : + glam::f32::Vec3 : Clone + Debug + Methods @@ -3680,20 +3764,21 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional vector with SIMD support. /// ///This type is 16 byte aligned. A SIMD vector type is used for storage on supported platforms for ///better performance than the `Vec3` type. /// ///It is possible to convert between `Vec3` and `Vec3A` types using `From` trait implementations. - glam::f32::sse2::vec3A::Vec3A : + glam::f32::Vec3A : Clone + Debug + Methods @@ -4027,17 +4112,18 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional vector with SIMD support. /// ///This type uses 16 byte aligned SIMD vector type for storage. - glam::f32::sse2::vec4::Vec4 : + glam::f32::Vec4 : Clone + Debug + Methods @@ -4346,15 +4432,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2-dimensional boolean vector. - glam::f32::sse2::vec2::BVec2 : + glam::bool::BVec2 : Clone + Debug + Methods @@ -4386,13 +4473,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional boolean vector. - glam::f32::sse2::vec3::BVec3 : + glam::bool::BVec3 : Clone + Debug + Methods @@ -4425,13 +4513,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional boolean vector. - glam::f32::sse2::vec4::BVec4 : + glam::bool::BVec4 : Clone + Debug + Methods @@ -4465,16 +4554,17 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional SIMD vector mask. /// ///This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available ///`BVec3A` will be a type alias for `BVec3`. - glam::f32::sse2::vec3::BVec3A : + glam::bool::BVec3A : Clone + Debug + Methods @@ -4504,16 +4594,17 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional SIMD vector mask. /// ///This type is 16 byte aligned and is backed by a SIMD vector. If SIMD is not available ///`BVec4A` will be a type alias for `BVec4`. - glam::f32::sse2::vec4::BVec4A : + glam::bool::BVec4A : Clone + Debug + Methods @@ -4543,13 +4634,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2-dimensional vector. - glam::f64::dvec2::DVec2 : + glam::f64::DVec2 : Clone + Debug + Methods @@ -4878,15 +4970,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional vector. - glam::f64::dvec3::DVec3 : + glam::f64::DVec3 : Clone + Debug + Methods @@ -5226,15 +5319,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional vector. - glam::f64::dvec4::DVec4 : + glam::f64::DVec4 : Clone + Debug + Methods @@ -5545,15 +5639,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,f64)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2-dimensional vector. - glam::i32::ivec2::IVec2 : + glam::i32::IVec2 : Clone + Debug + Methods @@ -5707,15 +5802,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional vector. - glam::i32::ivec3::IVec3 : + glam::i32::IVec3 : Clone + Debug + Methods @@ -5869,15 +5965,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional vector. - glam::i32::ivec4::IVec4 : + glam::i32::IVec4 : Clone + Debug + Methods @@ -6023,15 +6120,16 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,i32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2-dimensional vector. - glam::u32::uvec2::UVec2 : + glam::u32::UVec2 : Clone + Debug + Methods @@ -6162,15 +6260,16 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3-dimensional vector. - glam::u32::uvec3::UVec3 : + glam::u32::UVec3 : Clone + Debug + Methods @@ -6313,15 +6412,16 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4-dimensional vector. - glam::u32::uvec4::UVec4 : + glam::u32::UVec4 : Clone + Debug + Methods @@ -6456,13 +6556,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { (MetaMethod::Index) => |_,s,idx: usize| {Ok(s.inner()?[idx])}; mut (MetaMethod::NewIndex) => |_,s,(idx,val): (usize,u32)| {s.val_mut(|s| Ok(s[idx] = val))?}; } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3x3 column major matrix. /// ///This 3x3 matrix type features convenience methods for creating and using linear and @@ -6487,7 +6588,7 @@ impl_script_newtype! { ///2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for ///vectors respectively. These methods assume that `Self` contains a valid affine ///transform. - glam::f32::mat3::Mat3 : + glam::f32::Mat3 : Clone + Debug + Methods @@ -6668,7 +6769,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -6697,8 +6798,9 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2x2 column major matrix. - glam::f32::sse2::mat2::Mat2 : + glam::f32::Mat2 : Clone + Debug + Methods @@ -6800,7 +6902,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -6829,6 +6931,7 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3x3 column major matrix. /// ///This 3x3 matrix type features convenience methods for creating and using linear and @@ -6853,7 +6956,7 @@ impl_script_newtype! { ///2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for ///vectors respectively. These methods assume that `Self` contains a valid affine ///transform. - glam::f32::sse2::mat3::Mat3A : + glam::f32::Mat3A : Clone + Debug + Methods @@ -7034,7 +7137,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -7063,6 +7166,7 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4x4 column major matrix. /// ///This 4x4 matrix type features convenience methods for creating and using affine transforms and @@ -7092,7 +7196,7 @@ impl_script_newtype! { /// ///The resulting perspective project can be use to transform 3D vectors as points with ///perspective correction using the [`Self::project_point3()`] convenience method. - glam::f32::sse2::mat4::Mat4 : + glam::f32::Mat4 : Clone + Debug + Methods @@ -7399,7 +7503,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -7428,8 +7532,9 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2x2 column major matrix. - glam::f64::dmat2::DMat2 : + glam::f64::DMat2 : Clone + Debug + Methods @@ -7533,7 +7638,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -7562,6 +7667,7 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3x3 column major matrix. /// ///This 3x3 matrix type features convenience methods for creating and using linear and @@ -7586,7 +7692,7 @@ impl_script_newtype! { ///2D inputs as 3D vectors with an implicit `z` value of `1` for points and `0` for ///vectors respectively. These methods assume that `Self` contains a valid affine ///transform. - glam::f64::dmat3::DMat3 : + glam::f64::DMat3 : Clone + Debug + Methods @@ -7763,7 +7869,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -7792,6 +7898,7 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 4x4 column major matrix. /// ///This 4x4 matrix type features convenience methods for creating and using affine transforms and @@ -7821,7 +7928,7 @@ impl_script_newtype! { /// ///The resulting perspective project can be use to transform 3D vectors as points with ///perspective correction using the [`Self::project_point3()`] convenience method. - glam::f64::dmat4::DMat4 : + glam::f64::DMat4 : Clone + Debug + Methods @@ -8118,7 +8225,7 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { mut (MetaMethod::Index) => |_,s,idx : usize| { @@ -8147,8 +8254,9 @@ impl_script_newtype! { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2D affine transform, which can represent translation, rotation, scaling and shear. - glam::f32::sse2::mat2::Affine2 : + glam::f32::Affine2 : Clone + Debug + Methods @@ -8245,13 +8353,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3D affine transform, which can represent translation, rotation, scaling and shear. - glam::f32::sse2::mat3::Affine3A : + glam::f32::Affine3A : Clone + Debug + Methods @@ -8392,13 +8501,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 2D affine transform, which can represent translation, rotation, scaling and shear. - glam::f64::sse2::mat2::DAffine2 : + glam::f64::DAffine2 : Clone + Debug + Methods @@ -8494,13 +8604,14 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A 3D affine transform, which can represent translation, rotation, scaling and shear. - glam::f64::sse2::mat3::DAffine3 : + glam::f64::DAffine3 : Clone + Debug + Methods @@ -8632,11 +8743,12 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A quaternion representing an orientation. /// ///This quaternion is intended to be of unit length but may denormalize due to @@ -8644,7 +8756,7 @@ impl_script_newtype! { ///operations are applied. /// ///This type is 16 byte aligned. - glam::f32::sse2::quat::Quat : + glam::f32::Quat : Clone + Debug + Methods @@ -8893,17 +9005,18 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///A quaternion representing an orientation. /// ///This quaternion is intended to be of unit length but may denormalize due to ///floating point "error creep" which can occur when successive quaternion ///operations are applied. - glam::f64::dquat::DQuat : + glam::f64::DQuat : Clone + Debug + Methods @@ -9152,11 +9265,12 @@ impl_script_newtype! { ( Neg self -> self ) - impl + lua impl { } } impl_script_newtype! { + #[languages(on_feature(lua))] ///Euler rotation sequences. /// ///The angles are applied starting from the right. @@ -9165,7 +9279,7 @@ impl_script_newtype! { ///YXZ can be used for yaw (y-axis), pitch (x-axis), roll (z-axis). /// ///The two-axis rotations (e.g. ZYZ) are not fully tested and have to be treated with caution. - glam::euler::EulerRot : + glam::EulerRot : Clone + Debug + Methods @@ -9180,310 +9294,422 @@ impl_script_newtype! { + UnaryOps ( ) - impl + lua impl { } } -impl_tealr_generic!(pub(crate) struct T); -impl_tealr_generic!(pub(crate) struct K); -impl_tealr_generic!(pub(crate) struct V); +#[cfg(feature = "lua")] +crate::impl_tealr_generic!(pub(crate) struct T); +#[cfg(feature = "lua")] #[derive(Default)] pub(crate) struct BevyAPIGlobals; -impl tealr::mlu::ExportInstances for BevyAPIGlobals { - fn add_instances<'lua, T: tealr::mlu::InstanceCollector<'lua>>( +#[cfg(feature = "lua")] +impl bevy_mod_scripting_lua::tealr::mlu::ExportInstances for BevyAPIGlobals { + fn add_instances<'lua, T: bevy_mod_scripting_lua::tealr::mlu::InstanceCollector<'lua>>( self, instances: &mut T, - ) -> LuaResult<()> { - instances.add_instance("Name".into(), tealr::mlu::UserDataProxy::::new)?; + ) -> bevy_mod_scripting_lua::tealr::mlu::mlua::Result<()> { + instances.add_instance( + "Name".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; instances.add_instance( "Children".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Text".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; - instances.add_instance("Text".into(), tealr::mlu::UserDataProxy::::new)?; instances.add_instance( "TextSection".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "Stopwatch".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Timer".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Entity".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; - instances.add_instance("Timer".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Entity".into(), tealr::mlu::UserDataProxy::::new)?; instances.add_instance( "Transform".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "GlobalTransform".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "TextureAtlasSprite".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "RenderLayers".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "Visibility".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "ComputedVisibility".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Color".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Aabb".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; - instances.add_instance("Color".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Aabb".into(), tealr::mlu::UserDataProxy::::new)?; instances.add_instance( "Frustum".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "CameraRenderGraph".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "HandleId".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Vec2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Vec3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Vec3A".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Vec4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "BVec2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "BVec3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "BVec4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "BVec3A".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "BVec4A".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DVec2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DVec3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DVec4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "IVec2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "IVec3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "IVec4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "UVec2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "UVec3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "UVec4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Mat3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Mat2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Mat3A".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Mat4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DMat2".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DMat3".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DMat4".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; - instances.add_instance("Vec2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Vec3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Vec3A".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Vec4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("BVec2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("BVec3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("BVec4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("BVec3A".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("BVec4A".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DVec2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DVec3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DVec4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("IVec2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("IVec3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("IVec4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("UVec2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("UVec3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("UVec4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Mat3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Mat2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Mat3A".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("Mat4".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DMat2".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DMat3".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DMat4".into(), tealr::mlu::UserDataProxy::::new)?; instances.add_instance( "Affine2".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "Affine3A".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "DAffine2".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, )?; instances.add_instance( "DAffine3".into(), - tealr::mlu::UserDataProxy::::new, + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "Quat".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "DQuat".into(), + bevy_mod_scripting_lua::tealr::mlu::UserDataProxy::::new, + )?; + instances.add_instance( + "world".into(), + crate::lua::util::DummyTypeName::::new, + )?; + instances.add_instance( + "script".into(), + crate::lua::util::DummyTypeName::::new, + )?; + instances.add_instance( + "entity".into(), + crate::lua::util::DummyTypeName::::new, )?; - instances.add_instance("Quat".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("DQuat".into(), tealr::mlu::UserDataProxy::::new)?; - instances.add_instance("world".into(), DummyTypeName::::new)?; - instances.add_instance("script".into(), DummyTypeName::::new)?; - instances.add_instance("entity".into(), DummyTypeName::::new)?; Ok(()) } } +#[cfg(feature = "lua")] pub struct LuaBevyAPIProvider; +#[cfg(feature = "lua")] impl APIProvider for LuaBevyAPIProvider { - type APITarget = Mutex; - type ScriptContext = Mutex; + type APITarget = Mutex; + type ScriptContext = Mutex; type DocTarget = LuaDocFragment; - fn attach_api(&mut self, ctx: &mut Self::APITarget) -> Result<(), crate::ScriptError> { + fn attach_api(&mut self, ctx: &mut Self::APITarget) -> Result<(), ScriptError> { let ctx = ctx .get_mut() .expect("Unable to acquire lock on Lua context"); - Ok(tealr::mlu::set_global_env(BevyAPIGlobals, ctx)?) + bevy_mod_scripting_lua::tealr::mlu::set_global_env(BevyAPIGlobals, ctx) + .map_err(|e| ScriptError::Other(e.to_string())) } fn get_doc_fragment(&self) -> Option { Some(LuaDocFragment::new(|tw| { - tw.document_global_instance::() - .expect("Something went wrong documenting globals") - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() - .process_type::() - .process_type::>() + tw + .document_global_instance::().expect("Something went wrong documenting globals") + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() + .process_type::() + .process_type::>() })) } fn register_with_app(&self, app: &mut App) { @@ -9603,21 +9829,21 @@ impl APIProvider for LuaBevyAPIProvider { app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); - app.register_foreign_lua_type::(); app.register_foreign_lua_type::(); + app.register_foreign_lua_type::(); } } diff --git a/bevy_script_api/src/lib.rs b/bevy_script_api/src/lib.rs new file mode 100644 index 0000000000..5f20c0f82d --- /dev/null +++ b/bevy_script_api/src/lib.rs @@ -0,0 +1,19 @@ +extern crate bevy; + +pub mod error; +#[cfg(feature = "lua")] +pub mod lua; +pub mod script_ref; +pub mod sub_reflect; +pub mod wrappers; + +pub use {script_ref::*, sub_reflect::*}; + +// re-export derive macros from other langs +pub use bevy_mod_scripting_derive::impl_script_newtype; +#[cfg(feature = "lua")] +pub use bevy_mod_scripting_lua_derive::impl_lua_newtype; + +pub(crate) mod generated; + +pub use parking_lot; diff --git a/src/api/lua/bevy/mod.rs b/bevy_script_api/src/lua/bevy/mod.rs similarity index 98% rename from src/api/lua/bevy/mod.rs rename to bevy_script_api/src/lua/bevy/mod.rs index e1cd00ea25..6697ca81c7 100644 --- a/src/api/lua/bevy/mod.rs +++ b/bevy_script_api/src/lua/bevy/mod.rs @@ -1,11 +1,12 @@ -use crate::{impl_tealr_type, ScriptData, ScriptRef}; -use ::bevy::ecs::system::Command; -use ::bevy::hierarchy::BuildWorldChildren; -use ::std::convert::AsRef; -use ::std::ops::Deref; -use ::std::sync::{Arc, Weak}; - -use ::bevy::{ +use crate::impl_tealr_type; +use std::convert::AsRef; +use std::ops::Deref; +use std::sync::{Arc, Weak}; + +use crate::script_ref::ScriptRef; +use bevy::ecs::system::Command; +use bevy::hierarchy::BuildWorldChildren; +use bevy::{ hierarchy::{Children, DespawnChildrenRecursive, DespawnRecursive, Parent}, prelude::{ReflectComponent, ReflectDefault, ReflectResource, World}, reflect::{ @@ -13,15 +14,16 @@ use ::bevy::{ TypeRegistration, TypeRegistry, }, }; - +use bevy_mod_scripting_core::prelude::*; +use bevy_mod_scripting_lua::tealr; use parking_lot::RwLock; - -pub use crate::api::generated::*; use tealr::mlu::{ mlua::{self}, TealData, TealDataMethods, }; +pub use crate::generated::*; + #[derive(Clone)] pub struct LuaTypeRegistration(Arc); impl_tealr_type!(LuaTypeRegistration); diff --git a/src/api/lua/mod.rs b/bevy_script_api/src/lua/mod.rs similarity index 85% rename from src/api/lua/mod.rs rename to bevy_script_api/src/lua/mod.rs index 904aae9ab0..24e065e206 100644 --- a/src/api/lua/mod.rs +++ b/bevy_script_api/src/lua/mod.rs @@ -1,8 +1,12 @@ +use ::std::any::TypeId; use ::std::borrow::Cow; -use crate::{impl_tealr_type, ReflectedValue, ScriptRef, ValueIndex}; +use crate::impl_tealr_type; +use ::bevy::prelude::App; -use ::bevy::reflect::{Reflect, TypeRegistry}; +use ::bevy::reflect::{FromType, GetTypeRegistration, Reflect, TypeRegistry, TypeRegistryArc}; + +use bevy_mod_scripting_lua::tealr; use tealr::mlu::mlua::MetaMethod; use tealr::mlu::{ @@ -11,10 +15,48 @@ use tealr::mlu::{ }; use tealr::TypeName; -use crate::api::lua::bevy::LuaWorld; +use crate::script_ref::{ReflectedValue, ScriptRef, ValueIndex}; + +use self::bevy::LuaWorld; pub mod bevy; pub mod std; +pub mod util; + +/// A trait allowing to register the [`LuaProxyable`] trait with the type registry for foreign types +/// +/// If you have access to the type you should prefer to use `#[reflect(LuaProxyable)]` instead. +/// This is exactly equivalent. +pub trait RegisterForeignLuaType { + /// Register an instance of `ReflecLuaProxyable` type data on this type's registration, + /// if a registration does not yet exist, creates one. + fn register_foreign_lua_type( + &mut self, + ) -> &mut Self; +} + +impl RegisterForeignLuaType for App { + fn register_foreign_lua_type( + &mut self, + ) -> &mut Self { + { + let registry = self.world.resource_mut::(); + let mut registry = registry.write(); + + let user_data = >::from_type(); + + if let Some(registration) = registry.get_mut(TypeId::of::()) { + registration.insert(user_data) + } else { + let mut registration = T::get_type_registration(); + registration.insert(user_data); + registry.add_registration(registration); + } + } + + self + } +} impl ValueIndex> for ScriptRef { type Output = Result; diff --git a/src/api/lua/std.rs b/bevy_script_api/src/lua/std.rs similarity index 92% rename from src/api/lua/std.rs rename to bevy_script_api/src/lua/std.rs index 6d9838d8e2..548d769e1c 100644 --- a/src/api/lua/std.rs +++ b/bevy_script_api/src/lua/std.rs @@ -2,14 +2,11 @@ use ::std::borrow::Cow; use ::std::marker::PhantomData; -use crate::{ - ApplyLua, FromLuaProxy, LuaProxyable, ReflectPathElem, ReflectionError, ScriptRef, ToLuaProxy, - ValueIndex, -}; - use bevy::reflect::FromReflect; use bevy::reflect::Reflect; +use bevy_mod_scripting_lua::tealr; + use tealr::mlu::mlua::MetaMethod; use tealr::mlu::TypedFunction; use tealr::mlu::{ @@ -21,30 +18,41 @@ use tealr::TypeName; use paste::paste; +use crate::{ + error::ReflectionError, + script_ref::{ScriptRef, ValueIndex}, + sub_reflect::ReflectPathElem, +}; + +use super::ApplyLua; +use super::FromLuaProxy; +use super::LuaProxyable; +use super::ToLuaProxy; + /// Implements custom user data for simple copy types which implement to and from lua macro_rules! impl_proxyable_by_copy( ( $($num_ty:ty),*) => { paste! { $( - impl LuaProxyable for $num_ty { - fn ref_to_lua< 'lua>(self_: crate::ScriptRef,lua: & 'lua tealr::mlu::mlua::Lua) -> tealr::mlu::mlua::Result > { + impl $crate::lua::LuaProxyable for $num_ty { + fn ref_to_lua< 'lua>(self_: $crate::script_ref::ScriptRef,lua: & 'lua tealr::mlu::mlua::Lua) -> tealr::mlu::mlua::Result > { self_.get_typed(|self_ : &Self| self_.to_lua(lua))? } - fn apply_lua< 'lua>(self_: &mut crate::ScriptRef,lua: & 'lua tealr::mlu::mlua::Lua,new_val:tealr::mlu::mlua::Value< 'lua>) -> tealr::mlu::mlua::Result<()> { + fn apply_lua< 'lua>(self_: &mut $crate::script_ref::ScriptRef,lua: & 'lua tealr::mlu::mlua::Lua,new_val:tealr::mlu::mlua::Value< 'lua>) -> tealr::mlu::mlua::Result<()> { self_.set_val(Self::from_lua(new_val,lua)?)?; Ok(()) } } - impl <'lua>FromLuaProxy<'lua> for $num_ty { + impl <'lua>$crate::lua::FromLuaProxy<'lua> for $num_ty { #[inline(always)] fn from_lua_proxy(new_value: Value<'lua>, lua: &'lua Lua) -> tealr::mlu::mlua::Result { Self::from_lua(new_value,lua) } } - impl <'lua>ToLuaProxy<'lua> for $num_ty { + impl <'lua>$crate::lua::ToLuaProxy<'lua> for $num_ty { #[inline(always)] fn to_lua_proxy(self, lua: &'lua Lua) -> tealr::mlu::mlua::Result> { self.to_lua(lua) @@ -255,13 +263,13 @@ impl< + std::fmt::Debug, > UserData for LuaVec { - fn add_methods<'lua, M: ::tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); - ::add_methods(&mut x); + fn add_methods<'lua, M: tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + let mut x = tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); } - fn add_fields<'lua, F: ::tealr::mlu::mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - let mut wrapper = ::tealr::mlu::UserDataWrapper::from_user_data_fields(fields); - ::add_fields(&mut wrapper) + fn add_fields<'lua, F: tealr::mlu::mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + let mut wrapper = tealr::mlu::UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } } diff --git a/src/util.rs b/bevy_script_api/src/lua/util.rs similarity index 51% rename from src/util.rs rename to bevy_script_api/src/lua/util.rs index b32778fbd4..85c065db96 100644 --- a/src/util.rs +++ b/bevy_script_api/src/lua/util.rs @@ -1,4 +1,6 @@ +use bevy_mod_scripting_lua::tealr; use std::marker::PhantomData; + use tealr::TypeName; /// forwards the TypeName implementation of T, useful for internal 'fake' global instances @@ -7,142 +9,114 @@ pub struct DummyTypeName { } impl DummyTypeName { - pub fn new(_: &tealr::mlu::mlua::Lua) -> tealr::mlu::mlua::Result { + pub fn new( + _: &bevy_mod_scripting_lua::tealr::mlu::mlua::Lua, + ) -> bevy_mod_scripting_lua::tealr::mlu::mlua::Result { Ok(Self { _ph: PhantomData::, }) } } -impl<'lua, T> tealr::mlu::mlua::ToLua<'lua> for DummyTypeName { +impl<'lua, T> bevy_mod_scripting_lua::tealr::mlu::mlua::ToLua<'lua> for DummyTypeName { fn to_lua( self, - _: &'lua tealr::mlu::mlua::Lua, - ) -> tealr::mlu::mlua::Result> { - Ok(tealr::mlu::mlua::Value::Nil) + _: &'lua bevy_mod_scripting_lua::tealr::mlu::mlua::Lua, + ) -> bevy_mod_scripting_lua::tealr::mlu::mlua::Result< + bevy_mod_scripting_lua::tealr::mlu::mlua::Value<'lua>, + > { + Ok(bevy_mod_scripting_lua::tealr::mlu::mlua::Value::Nil) } } -impl tealr::TypeName for DummyTypeName { - fn get_type_parts() -> std::borrow::Cow<'static, [tealr::NamePart]> { +impl bevy_mod_scripting_lua::tealr::TypeName for DummyTypeName { + fn get_type_parts() -> std::borrow::Cow<'static, [bevy_mod_scripting_lua::tealr::NamePart]> { T::get_type_parts() } } -/// generates path to the given script depending on build configuration. -/// (optimized builds don't have the teal compiler available) -/// -/// Current configuration will provide ".tl" paths -/// ```rust -/// use bevy_mod_scripting::lua_path; -/// assert_eq!("scripts/my_script.tl",lua_path!("my_script")) -/// ``` -#[cfg(all(feature = "teal", debug_assertions))] -#[macro_export] -macro_rules! lua_path { - ($v:literal) => { - concat!("scripts/", $v, ".tl") - }; -} - -/// generates path to the given script depending on build configuration. -/// (optimized builds don't have the teal compiler available) -/// -/// Current configuration will provide ".lua" paths -/// ```rust -/// use bevy_mod_scripting::lua_path; -/// assert_eq!("scripts/build/my_script.lua",lua_path!("my_script")) -/// ``` -#[cfg(all(feature = "teal", not(debug_assertions)))] -#[macro_export] -macro_rules! lua_path { - ($v:literal) => { - concat!("scripts/build/", $v, ".lua") - }; -} - -/// Implements tealr::TypeName,tealr::TypeBody and mlua::Userdata based on non-generic single token type name implementing TealData +/// Implements :tealr::TypeName, tealr::TypeBody and mlua::Userdata based on non-generic single token type name implementing TealData #[macro_export] macro_rules! impl_tealr_type { ($v:ty) => { - impl tealr::TypeName for $v { - fn get_type_parts() -> ::std::borrow::Cow<'static, [tealr::NamePart]> { - ::std::borrow::Cow::Borrowed(&[tealr::NamePart::Type(tealr::TealType { + impl bevy_mod_scripting_lua::tealr::TypeName for $v { + fn get_type_parts() -> ::std::borrow::Cow<'static, [bevy_mod_scripting_lua::tealr::NamePart]> { + ::std::borrow::Cow::Borrowed(&[bevy_mod_scripting_lua::tealr::NamePart::Type(bevy_mod_scripting_lua::tealr::TealType { name: ::std::borrow::Cow::Borrowed(stringify!($v)), generics: None, - type_kind: tealr::KindOfType::External, + type_kind: bevy_mod_scripting_lua::tealr::KindOfType::External, })]) } } - impl mlua::UserData for $v { - fn add_fields<'lua, F: mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) { - let mut wrapper = ::tealr::mlu::UserDataWrapper::from_user_data_fields(fields); - ::add_fields(&mut wrapper) + impl bevy_mod_scripting_lua::tealr::mlu::mlua::UserData for $v { + fn add_fields<'lua, F: bevy_mod_scripting_lua::tealr::mlu::mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) { + let mut wrapper = ::bevy_mod_scripting_lua::tealr::mlu::UserDataWrapper::from_user_data_fields(fields); + ::add_fields(&mut wrapper) } - fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>( + fn add_methods<'lua, M: bevy_mod_scripting_lua::tealr::mlu::mlua::prelude::LuaUserDataMethods<'lua, Self>>( methods: &mut M, ) { - let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); - ::add_methods(&mut x); + let mut x = ::bevy_mod_scripting_lua::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); + ::add_methods(&mut x); } } - impl tealr::TypeBody for $v { - fn get_type_body() -> tealr::TypeGenerator { - let mut gen = ::tealr::RecordGenerator::new::(false); + impl bevy_mod_scripting_lua::tealr::TypeBody for $v { + fn get_type_body() -> bevy_mod_scripting_lua::tealr::TypeGenerator { + let mut gen = ::bevy_mod_scripting_lua::tealr::RecordGenerator::new::(false); gen.is_user_data = true; - ::add_fields(&mut gen); - ::add_methods(&mut gen); + ::add_fields(&mut gen); + ::add_methods(&mut gen); <_ as ::std::convert::From<_>>::from(gen) } } }; } -/// like create_tealr_union but translates to `any` in the lua declaration file, +/// like create_bevy_mod_scripting_lua::tealr_union but translates to `any` in the lua declaration file, /// a fill in to allow multiple userdata types #[macro_export] macro_rules! impl_tealr_any_union { ($visibility:vis $(Derives($($derives:ident), +))? enum $type_name:ident = $($sub_types:ident) | +) => { - #[derive(Clone,$($($derives ,)*)*)] + #[derive($($($derives ,)*)*)] #[allow(non_camel_case_types)] $visibility enum $type_name { $($sub_types($sub_types) ,)* } - impl<'lua> ::tealr::mlu::mlua::ToLua<'lua> for $type_name { - fn to_lua(self, lua: &'lua ::tealr::mlu::mlua::Lua) -> ::std::result::Result<::tealr::mlu::mlua::Value<'lua>, ::tealr::mlu::mlua::Error> { + impl<'lua> ::bevy_mod_scripting_lua::tealr::mlu::mlua::ToLua<'lua> for $type_name { + fn to_lua(self, lua: &'lua ::bevy_mod_scripting_lua::tealr::mlu::mlua::Lua) -> ::std::result::Result<::bevy_mod_scripting_lua::tealr::mlu::mlua::Value<'lua>, ::bevy_mod_scripting_lua::tealr::mlu::mlua::Error> { match self { $($type_name::$sub_types(x) => x.to_lua(lua),)* } } } - impl<'lua> ::tealr::mlu::mlua::FromLua<'lua> for $type_name { - fn from_lua(value: ::tealr::mlu::mlua::Value<'lua>, lua: &'lua ::tealr::mlu::mlua::Lua) -> ::std::result::Result { + impl<'lua> ::bevy_mod_scripting_lua::tealr::mlu::mlua::FromLua<'lua> for $type_name { + fn from_lua(value: ::bevy_mod_scripting_lua::tealr::mlu::mlua::Value<'lua>, lua: &'lua ::bevy_mod_scripting_lua::tealr::mlu::mlua::Lua) -> ::std::result::Result { $(match $sub_types::from_lua(value.clone(),lua) { Ok(x) => return Ok($type_name::$sub_types(x)), - Err(::tealr::mlu::mlua::Error::FromLuaConversionError{from:_,to:_,message:_}) => {} + Err(::bevy_mod_scripting_lua::tealr::mlu::mlua::Error::FromLuaConversionError{from:_,to:_,message:_}) => {} Err(x) => return Err(x) };)* - Err(::tealr::mlu::mlua::Error::FromLuaConversionError{ + Err(::bevy_mod_scripting_lua::tealr::mlu::mlua::Error::FromLuaConversionError{ to: stringify!( $($sub_types)|* ), from: value.type_name(), message: None }) } } - impl ::tealr::TypeName for $type_name { - fn get_type_parts() -> ::std::borrow::Cow<'static,[::tealr::NamePart]> { - ::std::borrow::Cow::Borrowed(&[::tealr::NamePart::Type(::tealr::TealType { + impl ::bevy_mod_scripting_lua::tealr::TypeName for $type_name { + fn get_type_parts() -> ::std::borrow::Cow<'static,[::bevy_mod_scripting_lua::tealr::NamePart]> { + ::std::borrow::Cow::Borrowed(&[::bevy_mod_scripting_lua::tealr::NamePart::Type(::bevy_mod_scripting_lua::tealr::TealType { name: ::std::borrow::Cow::Borrowed("any"), generics: None, - type_kind: ::tealr::KindOfType::Builtin, + type_kind: ::bevy_mod_scripting_lua::tealr::KindOfType::Builtin, })]) } - fn get_type_kind() -> ::tealr::KindOfType { - ::tealr::KindOfType::Builtin + fn get_type_kind() -> ::bevy_mod_scripting_lua::tealr::KindOfType { + ::bevy_mod_scripting_lua::tealr::KindOfType::Builtin } } }; @@ -156,9 +130,9 @@ macro_rules! impl_tealr_generic{ #[derive(Default,Clone,Debug)] $vis struct $name; - impl $crate::ValueLuaType for $name {} + impl $crate::lua::ValueLuaType for $name {} - impl ::tealr::mlu::TealData for $name { + impl ::bevy_mod_scripting_lua::tealr::mlu::TealData for $name { } @@ -228,14 +202,14 @@ macro_rules! impl_tealr_generic{ // /// ``` // macro_rules! impl_user_data { // ($v:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt $(<'a>)? )* )? ),+ >)? ) => { -// impl $(< $( $lt $( : $clt $(+ $dlt $(<'a>)?)* )? ),+ >)? ::tealr::mlu::mlua::UserData for $v $(< $( $lt ),+ >)? { -// fn add_methods<'lua, M: ::tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { -// let mut x = ::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); -// ::add_methods(&mut x); +// impl $(< $( $lt $( : $clt $(+ $dlt $(<'a>)?)* )? ),+ >)? ::bevy_mod_scripting_lua::tealr::mlu::mlua::UserData for $v $(< $( $lt ),+ >)? { +// fn add_methods<'lua, M: ::bevy_mod_scripting_lua::tealr::mlu::mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { +// let mut x = ::bevy_mod_scripting_lua::tealr::mlu::UserDataWrapper::from_user_data_methods(methods); +// ::add_methods(&mut x); // } -// fn add_fields<'lua, F: ::tealr::mlu::mlua::UserDataFields<'lua, Self>>(fields: &mut F) { -// let mut wrapper = ::tealr::mlu::UserDataWrapper::from_user_data_fields(fields); -// ::add_fields(&mut wrapper) +// fn add_fields<'lua, F: ::bevy_mod_scripting_lua::tealr::mlu::mlua::UserDataFields<'lua, Self>>(fields: &mut F) { +// let mut wrapper = ::bevy_mod_scripting_lua::tealr::mlu::UserDataWrapper::from_user_data_fields(fields); +// ::add_fields(&mut wrapper) // } // } diff --git a/src/api/script_ref.rs b/bevy_script_api/src/script_ref.rs similarity index 63% rename from src/api/script_ref.rs rename to bevy_script_api/src/script_ref.rs index 39ac22dd51..e5c6043524 100644 --- a/src/api/script_ref.rs +++ b/bevy_script_api/src/script_ref.rs @@ -1,5 +1,7 @@ -use crate::{ReflectBase, ReflectPath, ReflectPathElem, ReflectionError}; -use anyhow::Result; +use crate::{ + error::ReflectionError, + sub_reflect::{ReflectBase, ReflectPath, ReflectPathElem}, +}; use std::fmt::Debug; @@ -243,144 +245,143 @@ impl From for ScriptRef { } } -#[cfg(test)] - -mod test { - use crate::{ - api::lua::bevy::LuaEntity, - langs::mlu::{mlua, mlua::prelude::*}, - ReflectPtr, ScriptRef, - }; - use bevy::{prelude::*, reflect::TypeRegistryArc}; - use parking_lot::RwLock; - use std::sync::Arc; - - #[derive(Clone)] - struct TestArg(LuaEntity); - - impl<'lua> ToLua<'lua> for TestArg { - fn to_lua(self, ctx: &'lua Lua) -> Result, mlua::Error> { - self.0.to_lua(ctx) - } - } - - #[derive(Component, Reflect, Default)] - #[reflect(Component)] - struct TestComponent { - mat3: Mat3, - } - - #[test] - #[should_panic] - fn miri_test_components() { - let world_arc = Arc::new(RwLock::new(World::new())); - - let mut component_ref1; - let mut component_ref2; - - { - let world = &mut world_arc.write(); - - world.init_resource::(); - let registry = world.resource_mut::(); - registry.write().register::(); - - let tst_comp = TestComponent { - mat3: Mat3::from_cols( - Vec3::new(1.0, 2.0, 3.0), - Vec3::new(4.0, 5.0, 6.0), - Vec3::new(7.0, 8.0, 9.0), - ), - }; - - let refl = registry - .read() - .get_with_short_name("TestComponent") - .and_then(|registration| registration.data::()) - .unwrap() - .clone(); - - let entity = world.spawn().insert(tst_comp).id(); - - let refl_ref = refl.reflect(world, entity).unwrap(); - let _ptr: ReflectPtr = (refl_ref as *const dyn Reflect).into(); - - component_ref1 = ScriptRef::new_component_ref(refl, entity, Arc::downgrade(&world_arc)); - component_ref2 = component_ref1.clone(); - } - // TODO: reformat this test now that we return results instead of panicking - component_ref1 - .get(|r1| { - component_ref2 - .get(|r2| { - let _ = r1.downcast_ref::().unwrap().mat3 - + r2.downcast_ref::().unwrap().mat3; - }) - .unwrap() - }) - .unwrap(); - - component_ref1 - .get_mut(|r1| { - let _ = r1.downcast_ref::().unwrap().mat3 * 2.0; - }) - .unwrap(); - - component_ref2 - .get_mut(|r2| { - let _ = r2.downcast_ref::().unwrap().mat3 * 2.0; - }) - .unwrap(); - - // invalid should panic here - component_ref1 - .get_mut(|r1| { - component_ref2 - .get(|r2| { - r1.downcast_mut::().unwrap().mat3 = - r2.downcast_ref::().unwrap().mat3; - }) - .unwrap() - }) - .unwrap(); - } - - // #[test] - // #[should_panic] - // fn miri_test_owned(){ - - // let mut mat = Mat3::from_cols(Vec3::new(1.0,2.0,3.0), - // Vec3::new(4.0,5.0,6.0), - // Vec3::new(7.0,8.0,9.0)); - - // let ptr : ReflectPtr = (mat.col_mut(0) as *mut dyn Reflect).into(); - // let valid = Arc::new(RwLock::new(())); - - // let mut ref1 = unsafe{ ScriptRef::new_script_ref(ptr, valid) - // ScriptRefBase::ScriptOwned{valid:Arc::downgrade(&valid)}, - // None, - // ptr.into() - // )}; - // let mut ref2 = ref1.clone(); - - // ref1.get(|r1| { - // ref2.get(|r2|{ - // let _ = *r1.downcast_ref::().unwrap() + *r2.downcast_ref::().unwrap(); - // }) - // }); - - // ref1.get_mut(|r1,_| { - // let _ = *r1.downcast_ref::().unwrap() * 2.0; - // }); - - // ref2.get_mut(|r2,_|{ - // let _ = *r2.downcast_ref::().unwrap() * 2.0; - // }); - - // drop(valid); - // drop(mat); - - // // should panic since original value dropped - // ref1.get_mut(|r1,_| r1.downcast_mut::().unwrap()[1] = 2.0); - // } -} +// #[cfg(test)] +// mod test { +// use crate::{ +// api::lua::bevy::LuaEntity, +// langs::mlu::{mlua, mlua::prelude::*}, +// ReflectPtr, ScriptRef, +// }; +// use bevy::{prelude::*, reflect::TypeRegistryArc}; +// use parking_lot::RwLock; +// use std::sync::Arc; + +// #[derive(Clone)] +// struct TestArg(LuaEntity); + +// impl<'lua> ToLua<'lua> for TestArg { +// fn to_lua(self, ctx: &'lua Lua) -> Result, mlua::Error> { +// self.0.to_lua(ctx) +// } +// } + +// #[derive(Component, Reflect, Default)] +// #[reflect(Component)] +// struct TestComponent { +// mat3: Mat3, +// } + +// #[test] +// #[should_panic] +// fn miri_test_components() { +// let world_arc = Arc::new(RwLock::new(World::new())); + +// let mut component_ref1; +// let mut component_ref2; + +// { +// let world = &mut world_arc.write(); + +// world.init_resource::(); +// let registry = world.resource_mut::(); +// registry.write().register::(); + +// let tst_comp = TestComponent { +// mat3: Mat3::from_cols( +// Vec3::new(1.0, 2.0, 3.0), +// Vec3::new(4.0, 5.0, 6.0), +// Vec3::new(7.0, 8.0, 9.0), +// ), +// }; + +// let refl = registry +// .read() +// .get_with_short_name("TestComponent") +// .and_then(|registration| registration.data::()) +// .unwrap() +// .clone(); + +// let entity = world.spawn().insert(tst_comp).id(); + +// let refl_ref = refl.reflect(world, entity).unwrap(); +// let _ptr: ReflectPtr = (refl_ref as *const dyn Reflect).into(); + +// component_ref1 = ScriptRef::new_component_ref(refl, entity, Arc::downgrade(&world_arc)); +// component_ref2 = component_ref1.clone(); +// } +// // TODO: reformat this test now that we return results instead of panicking +// component_ref1 +// .get(|r1| { +// component_ref2 +// .get(|r2| { +// let _ = r1.downcast_ref::().unwrap().mat3 +// + r2.downcast_ref::().unwrap().mat3; +// }) +// .unwrap() +// }) +// .unwrap(); + +// component_ref1 +// .get_mut(|r1| { +// let _ = r1.downcast_ref::().unwrap().mat3 * 2.0; +// }) +// .unwrap(); + +// component_ref2 +// .get_mut(|r2| { +// let _ = r2.downcast_ref::().unwrap().mat3 * 2.0; +// }) +// .unwrap(); + +// // invalid should panic here +// component_ref1 +// .get_mut(|r1| { +// component_ref2 +// .get(|r2| { +// r1.downcast_mut::().unwrap().mat3 = +// r2.downcast_ref::().unwrap().mat3; +// }) +// .unwrap() +// }) +// .unwrap(); +// } + +// #[test] +// #[should_panic] +// fn miri_test_owned(){ + +// let mut mat = Mat3::from_cols(Vec3::new(1.0,2.0,3.0), +// Vec3::new(4.0,5.0,6.0), +// Vec3::new(7.0,8.0,9.0)); + +// let ptr : ReflectPtr = (mat.col_mut(0) as *mut dyn Reflect).into(); +// let valid = Arc::new(RwLock::new(())); + +// let mut ref1 = unsafe{ ScriptRef::new_script_ref(ptr, valid) +// ScriptRefBase::ScriptOwned{valid:Arc::downgrade(&valid)}, +// None, +// ptr.into() +// )}; +// let mut ref2 = ref1.clone(); + +// ref1.get(|r1| { +// ref2.get(|r2|{ +// let _ = *r1.downcast_ref::().unwrap() + *r2.downcast_ref::().unwrap(); +// }) +// }); + +// ref1.get_mut(|r1,_| { +// let _ = *r1.downcast_ref::().unwrap() * 2.0; +// }); + +// ref2.get_mut(|r2,_|{ +// let _ = *r2.downcast_ref::().unwrap() * 2.0; +// }); + +// drop(valid); +// drop(mat); + +// // should panic since original value dropped +// ref1.get_mut(|r1,_| r1.downcast_mut::().unwrap()[1] = 2.0); +// } +// } diff --git a/src/api/sub_reflect.rs b/bevy_script_api/src/sub_reflect.rs similarity index 99% rename from src/api/sub_reflect.rs rename to bevy_script_api/src/sub_reflect.rs index 61abcfaf33..735cf74522 100644 --- a/src/api/sub_reflect.rs +++ b/bevy_script_api/src/sub_reflect.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, sync::Weak}; +use crate::error::ReflectionError; use bevy::{ prelude::{Entity, ReflectComponent, ReflectResource, World}, reflect::{Reflect, ReflectMut, ReflectRef}, @@ -103,7 +104,7 @@ pub enum ReflectPathElem { } use std::fmt::{Debug, Display}; -use crate::{ReflectPtr, ReflectionError}; +use crate::script_ref::ReflectPtr; impl Debug for ReflectPathElem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/src/api/wrappers.rs b/bevy_script_api/src/wrappers.rs similarity index 90% rename from src/api/wrappers.rs rename to bevy_script_api/src/wrappers.rs index cec56c0eee..6a4c0e8481 100644 --- a/src/api/wrappers.rs +++ b/bevy_script_api/src/wrappers.rs @@ -14,7 +14,7 @@ macro_rules! ref_only_wrapper_methods { /// Creates a script reference pointing to the wrapped value. /// /// Depending on this value it may be a lua owned or reflect relative reference - pub fn script_ref(&self) -> $crate::ScriptRef { + pub fn script_ref(&self) -> $crate::script_ref::ScriptRef { match self { Self::Owned(val, valid) => unsafe { // safety: @@ -22,7 +22,7 @@ macro_rules! ref_only_wrapper_methods { // - using the valid lock means no incorrect aliasing may occur // - the pointer points to base of the reference // invariants are upheld - $crate::ScriptRef::new_script_ref( + $crate::script_ref::ScriptRef::new_script_ref( (val.get() as *mut dyn ::bevy::reflect::Reflect).into(), ::std::sync::Arc::downgrade(valid), ) @@ -34,17 +34,17 @@ macro_rules! ref_only_wrapper_methods { pub fn new(b: $type_) -> Self { Self::Owned( ::std::cell::UnsafeCell::new(b), - ::std::sync::Arc::new(::parking_lot::RwLock::new(())), + ::std::sync::Arc::new($crate::parking_lot::RwLock::new(())), ) } - pub fn new_ref(b: $crate::ScriptRef) -> Self { + pub fn new_ref(b: $crate::script_ref::ScriptRef) -> Self { Self::Ref(b) } /// Perform an operation on the base type and optionally retrieve something by value /// may require a read lock on the world in case this is a reference - pub fn val(&self, accessor: F) -> Result + pub fn val(&self, accessor: F) -> Result where F: FnOnce(&$type_) -> G, { @@ -61,7 +61,7 @@ macro_rules! ref_only_wrapper_methods { } } - pub fn val_mut(&mut self, accessor: F) -> Result + pub fn val_mut(&mut self, accessor: F) -> Result where F: FnOnce(&mut $type_) -> G, { @@ -81,8 +81,8 @@ macro_rules! ref_only_wrapper_methods { /// may require a write lock on the world pub fn apply_self_to_base( &self, - other: &mut $crate::ScriptRef, - ) -> Result<(), $crate::ReflectionError> { + other: &mut $crate::script_ref::ScriptRef, + ) -> Result<(), $crate::error::ReflectionError> { match self { Self::Owned(v, valid) => { let lock = valid.read(); @@ -107,8 +107,8 @@ macro_rules! define_wrapper{ #[allow(clippy::large_enum_variant)] #[doc=concat!("A script wrapper for the type `",stringify!($type_),"`")] pub enum $wrapper_name{ - Owned(::std::cell::UnsafeCell<$type_>, ::std::sync::Arc<::parking_lot::RwLock<()>>), - Ref($crate::ScriptRef), + Owned(::std::cell::UnsafeCell<$type_>, ::std::sync::Arc<$crate::parking_lot::RwLock<()>>), + Ref($crate::script_ref::ScriptRef), } /// Safety: we make this sync via RwLock<()> assuming invariants are upheld @@ -139,7 +139,7 @@ macro_rules! make_script_wrapper { $crate::ref_only_wrapper_methods!($type_, $wrapper_name); /// retrieves the underlying value by cloning it - pub fn inner(&self) -> Result<$type_, $crate::ReflectionError> + pub fn inner(&self) -> Result<$type_, $crate::error::ReflectionError> where $type_: Clone, { @@ -155,7 +155,7 @@ macro_rules! make_script_wrapper { self.val(|s| s.clone()) .expect("Rust aliasing rules broken in cloning wrapper"), ), - ::std::sync::Arc::new(::parking_lot::RwLock::new(())), + ::std::sync::Arc::new($crate::parking_lot::RwLock::new(())), ), Self::Ref(v) => Self::Ref(v.clone()), } diff --git a/examples/lua/bevy_api.rs b/examples/lua/bevy_api.rs index 6d90e347ec..f3427a70d7 100644 --- a/examples/lua/bevy_api.rs +++ b/examples/lua/bevy_api.rs @@ -1,11 +1,10 @@ use bevy::app::AppExit; use bevy::math::DQuat; use bevy::prelude::*; -use bevy_mod_scripting::{ - langs::mlu::mlua::{self, UserData}, - lua::bevy::LuaBevyAPIProvider, - AddScriptApiProvider, AddScriptHost, LuaEvent, LuaScriptHost, Recipients, ReflectLuaProxyable, - RegisterForeignLuaType, ScriptHost, ScriptingPlugin, ValueLuaType, +use bevy_mod_scripting::prelude::*; +use bevy_mod_scripting_lua::tealr::mlu::mlua::UserData; +use bevy_script_api::lua::{ + bevy::LuaBevyAPIProvider, ReflectLuaProxyable, RegisterForeignLuaType, ValueLuaType, }; /// Let's define a resource, we want it to be "assignable" via lua so we derive `ReflectLuaProxyable` diff --git a/examples/lua/complex_game_loop.rs b/examples/lua/complex_game_loop.rs index e7026bbcf5..0f13cd9a5f 100644 --- a/examples/lua/complex_game_loop.rs +++ b/examples/lua/complex_game_loop.rs @@ -1,13 +1,6 @@ use bevy::prelude::*; use bevy::time::FixedTimestep; -use bevy_event_priority::PriorityEventWriter; -use bevy_mod_scripting::{ - langs::mlu::{mlua, mlua::prelude::*, mlua::Value}, - mlu::mlua::Variadic, - APIProvider, AddScriptApiProvider, AddScriptHost, AddScriptHostHandler, LuaDocFragment, - LuaEvent, LuaFile, LuaScriptHost, Recipients, Script, ScriptCollection, ScriptData, - ScriptError, ScriptingPlugin, -}; +use bevy_mod_scripting::prelude::*; use rand::prelude::SliceRandom; use std::sync::atomic::Ordering::Relaxed; use std::sync::{atomic::AtomicU32, Mutex}; @@ -38,13 +31,16 @@ impl APIProvider for LuaAPIProvider { let ctx = ctx.get_mut().unwrap(); - ctx.globals().set( - "print", - ctx.create_function(|_ctx, msg: String| { - info!("{}", msg); - Ok(()) - })?, - )?; + ctx.globals() + .set( + "print", + ctx.create_function(|_ctx, msg: String| { + info!("{}", msg); + Ok(()) + }) + .map_err(ScriptError::new_other)?, + ) + .map_err(ScriptError::new_other)?; Ok(()) } @@ -62,7 +58,7 @@ static COUNTER: AtomicU32 = AtomicU32::new(0); /// utility for generating random events from a list fn fire_random_event( - w: &mut PriorityEventWriter>>, + w: &mut PriorityEventWriter>>, events: &[ScriptEventData], ) { let mut rng = rand::thread_rng(); @@ -71,7 +67,7 @@ fn fire_random_event( let (event, prio) = events .choose(&mut rng) .map(|v| { - let mut args = Variadic::new(); + let mut args = mlua::Variadic::new(); args.push(arg); ( LuaEvent { @@ -91,7 +87,7 @@ fn fire_random_event( w.send(event, prio); } -fn do_some_shit_before_physics(mut w: PriorityEventWriter>>) { +fn do_some_shit_before_physics(mut w: PriorityEventWriter>>) { info!("PrePhysics, firing:"); for _ in 0..5 { @@ -100,7 +96,7 @@ fn do_some_shit_before_physics(mut w: PriorityEventWriter>>) { +fn do_physics(mut w: PriorityEventWriter>>) { info!("Physics, firing:"); for _ in 0..5 { @@ -109,7 +105,7 @@ fn do_physics(mut w: PriorityEventWriter>>) { } } -fn do_update(mut w: PriorityEventWriter>>) { +fn do_update(mut w: PriorityEventWriter>>) { info!("Update, firing:"); // fire random event, for any stages @@ -180,7 +176,7 @@ fn main() -> std::io::Result<()> { PRE_PHYSICS_SCRIPTS, SystemStage::single_threaded(), ) - .add_script_handler_stage_with_criteria::>, _, _, _, 0, 10>( + .add_script_handler_stage_with_criteria::>, _, _, _, 0, 10>( PRE_PHYSICS_SCRIPTS, FixedTimestep::step(TIMESTEP_2_PER_SECOND), ) @@ -191,7 +187,7 @@ fn main() -> std::io::Result<()> { POST_PHYSICS_SCRIPTS, SystemStage::single_threaded(), ) - .add_script_handler_stage_with_criteria::>, _, _, _, 11, 20>( + .add_script_handler_stage_with_criteria::>, _, _, _, 11, 20>( POST_PHYSICS_SCRIPTS, FixedTimestep::step(TIMESTEP_2_PER_SECOND), ) @@ -203,10 +199,10 @@ fn main() -> std::io::Result<()> { POST_UPDATE_SCRIPTS, SystemStage::single_threaded(), ) - .add_script_handler_stage::>, _, 21, 30>(POST_UPDATE_SCRIPTS) + .add_script_handler_stage::>, _, 21, 30>(POST_UPDATE_SCRIPTS) // this stage handles addition and removal of script contexts, we can safely use `CoreStage::PostUpdate` - .add_script_host::>, _>(CoreStage::PostUpdate) - .add_api_provider::>>(Box::new(LuaAPIProvider)); + .add_script_host::>, _>(CoreStage::PostUpdate) + .add_api_provider::>>(Box::new(LuaAPIProvider)); // We have 3 core systems // PrePhysics (twice per second), fires 5 random events diff --git a/examples/lua/documentation_gen.rs b/examples/lua/documentation_gen.rs index 76977c13a2..3b8b4e545e 100644 --- a/examples/lua/documentation_gen.rs +++ b/examples/lua/documentation_gen.rs @@ -1,12 +1,9 @@ use bevy::prelude::*; use bevy_mod_scripting::{ - api::lua::bevy::LuaBevyAPIProvider, - langs::mlu::{mlua, mlua::prelude::*, mlua::Value, TealData}, - APIProvider, AddScriptApiProvider, AddScriptHost, AddScriptHostHandler, GenDocumentation, - LuaDocFragment, LuaScriptHost, ScriptError, ScriptingPlugin, + api::{impl_tealr_type, lua::bevy::LuaBevyAPIProvider}, + prelude::*, }; -use tealr::TypeName; use std::sync::Mutex; @@ -19,12 +16,14 @@ impl<'lua> ToLua<'lua> for MyLuaArg { } } -#[derive(Clone, tealr::mlu::UserData, TypeName)] +#[derive(Clone)] /// This is acts as a documentation and function holder /// We can add some general documentation about what it holds /// but also specific function level documenation pub struct APIModule; +impl_tealr_type!(APIModule); + impl TealData for APIModule { fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { methods @@ -76,7 +75,7 @@ impl APIProvider for LuaAPIProvider { let ctx = ctx.get_mut().unwrap(); // equivalent to ctx.globals().set() but for multiple items - tealr::mlu::set_global_env(Export, ctx)?; + tealr::mlu::set_global_env(Export, ctx).map_err(ScriptError::new_other)?; Ok(()) } diff --git a/examples/lua/event_recipients.rs b/examples/lua/event_recipients.rs index ffdac3aee6..bce0b83011 100644 --- a/examples/lua/event_recipients.rs +++ b/examples/lua/event_recipients.rs @@ -1,11 +1,5 @@ use bevy::prelude::*; -use bevy_event_priority::PriorityEventWriter; -use bevy_mod_scripting::{ - langs::mlu::{mlua, mlua::prelude::*, mlua::Value}, - APIProvider, AddScriptApiProvider, AddScriptHost, AddScriptHostHandler, LuaDocFragment, - LuaEvent, LuaFile, LuaScriptHost, Recipients, Script, ScriptCollection, ScriptData, - ScriptError, ScriptingPlugin, -}; +use bevy_mod_scripting::prelude::*; use rand::prelude::SliceRandom; use std::sync::atomic::Ordering::Relaxed; use std::sync::{atomic::AtomicU32, Mutex}; @@ -36,13 +30,16 @@ impl APIProvider for LuaAPIProvider { let ctx = ctx.get_mut().unwrap(); - ctx.globals().set( - "print", - ctx.create_function(|_ctx, msg: String| { - info!("{}", msg); - Ok(()) - })?, - )?; + ctx.globals() + .set( + "print", + ctx.create_function(|_ctx, msg: String| { + info!("{}", msg); + Ok(()) + }) + .map_err(ScriptError::new_other)?, + ) + .map_err(ScriptError::new_other)?; Ok(()) } diff --git a/examples/lua/game_of_life.rs b/examples/lua/game_of_life.rs index cce89eb93f..9f3e9ba02a 100644 --- a/examples/lua/game_of_life.rs +++ b/examples/lua/game_of_life.rs @@ -11,9 +11,14 @@ use bevy::{ time::FixedTimestep, window::WindowResized, }; + use bevy_mod_scripting::{ - api::lua::bevy::LuaBevyAPIProvider, langs::mlu::mlua, lua_path, prelude::*, std::LuaVec, - ReflectLuaProxyable, + api::{ + impl_lua_newtype, impl_script_newtype, + lua::{bevy::LuaBevyAPIProvider, std::LuaVec, LuaProxyable, ReflectLuaProxyable}, + ValueIndex, + }, + prelude::*, }; #[derive(Debug, Default, Reflect, Component)] @@ -23,8 +28,9 @@ pub struct LifeState { } impl_script_newtype!( + #[languages(lua)] LifeState : Debug - impl { + lua impl { get "cells" => |lua,s: &LuaLifeState| { Ok(LuaVec::::new_ref(s.script_ref().index(Cow::Borrowed("cells")))) }; @@ -102,7 +108,7 @@ pub fn setup( image.sampler_descriptor = ImageSampler::nearest(); // in release builds we want to fetch ".lua" files over ".tl" files - let script_path = lua_path!("game_of_life"); + let script_path = bevy_mod_scripting_lua::lua_path!("game_of_life"); commands.spawn_bundle(Camera2dBundle::default()); commands diff --git a/examples/rhai/bevy_api.rs b/examples/rhai/bevy_api.rs new file mode 100644 index 0000000000..a72a8027e7 --- /dev/null +++ b/examples/rhai/bevy_api.rs @@ -0,0 +1,44 @@ +use bevy::app::AppExit; +use bevy::prelude::*; +use bevy_mod_scripting::prelude::*; +use bevy_mod_scripting_rhai::{RhaiEvent, RhaiScriptHost}; +/// Let's define a resource, we want it to be "assignable" via lua so we derive `ReflectLuaProxyable` +/// This allows us to reach this value when it's a field under any other Reflectable type + +fn main() -> std::io::Result<()> { + let mut app = App::new(); + + app.add_plugins(DefaultPlugins) + .add_plugin(ScriptingPlugin) + .add_script_host::, _>(CoreStage::PostUpdate) + .add_system( + (|world: &mut World| { + // run script + world.resource_scope(|world, mut host: Mut>| { + host.run_one_shot( + r#" + fn once(){ + print("hello") + } + "# + .as_bytes(), + "script.rhai", + world, + RhaiEvent { + hook_name: "once".to_owned(), + args: (), + recipients: Recipients::All, + }, + ) + .expect("Something went wrong in the script!"); + }); + + world.send_event(AppExit) + }) + .exclusive_system(), + ); + + app.run(); + + Ok(()) +} diff --git a/examples/wrappers.rs b/examples/wrappers.rs index caa2484342..924541740b 100644 --- a/examples/wrappers.rs +++ b/examples/wrappers.rs @@ -1,10 +1,9 @@ -use bevy::app::AppExit; -use bevy::prelude::*; -use bevy::reflect::TypeRegistryArc; -use bevy_mod_scripting::{api::lua::bevy::LuaWorld, ScriptRef}; -use bevy_mod_scripting::{langs::mlu::mlua, AddScriptHost, LuaEvent, Recipients, ScriptingPlugin}; -use bevy_mod_scripting::{LuaScriptHost, ScriptHost}; -use bevy_mod_scripting_derive::impl_script_newtype; +use bevy::{app::AppExit, prelude::*, reflect::TypeRegistryArc}; + +use bevy_mod_scripting::{ + api::{impl_lua_newtype, impl_script_newtype, lua::bevy::LuaWorld, ScriptRef}, + prelude::*, +}; // Step 1. Rust representation // construct all our types and functionality @@ -37,6 +36,7 @@ impl MyThing { // The bevy API, however doing this means your provide static typing for your scripts in languages which support it, // To see what else this macro can do see `src/api/generated.rs` impl_script_newtype!( + #[languages(lua)] MyThing: Debug + Clone + Fields( @@ -51,7 +51,7 @@ impl_script_newtype!( do_something_cool(&self:) ) - impl { + lua impl { // we can also directly add methods to the underlying script traits using their specific syntax // note that in this case you need to provide an implementation for every language you want to support, // the flags above automatically do this for you. diff --git a/languages/bevy_mod_scripting_lua/Cargo.toml b/languages/bevy_mod_scripting_lua/Cargo.toml new file mode 100644 index 0000000000..989a2ed5b6 --- /dev/null +++ b/languages/bevy_mod_scripting_lua/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "bevy_mod_scripting_lua" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Necessary functionality for Lua support with bevy_mod_scripting" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "rhai"] +categories = ["game-development"] +readme="readme.md" + +[features] +# enables loading possibly unsafe lua modules by lua scripts +unsafe_lua_modules = [] + +# enable teal utilities +teal = [] + +lua51 = ["tealr/mlua_lua51"] +lua52 = ["tealr/mlua_lua52"] +lua53 = ["tealr/mlua_lua53"] +lua54 = ["tealr/mlua_lua54"] +luajit = ["tealr/mlua_luajit"] +luajit52 = ["tealr/mlua_luajit52"] +mlua_serialize = ["tealr/mlua_serialize"] +mlua_macros = ["tealr/mlua_macros"] + +[lib] +name="bevy_mod_scripting_lua" +path="src/lib.rs" + +[dependencies] +bevy= { version = "0.8.0", default-features = false} +bevy_mod_scripting_core = {path="../../bevy_mod_scripting_core", version="0.1.1"} +tealr = { version = "0.9.0-alpha1", features=["mlua_vendored","mlua_send"]} +parking_lot = "0.12.1" +serde_json = "1.0.81" +serde = { version = "1", features = ["derive"] } + + diff --git a/languages/bevy_mod_scripting_lua/readme.md b/languages/bevy_mod_scripting_lua/readme.md new file mode 100644 index 0000000000..f45d66e632 --- /dev/null +++ b/languages/bevy_mod_scripting_lua/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_lua + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/src/hosts/mlua_host/assets.rs b/languages/bevy_mod_scripting_lua/src/assets.rs similarity index 93% rename from src/hosts/mlua_host/assets.rs rename to languages/bevy_mod_scripting_lua/src/assets.rs index f478d20a49..dd66acd6fb 100644 --- a/src/hosts/mlua_host/assets.rs +++ b/languages/bevy_mod_scripting_lua/src/assets.rs @@ -1,8 +1,8 @@ -use crate::CodeAsset; use bevy::{ - asset::{AssetLoader, LoadedAsset}, + asset::{AssetLoader, Error, LoadedAsset}, reflect::TypeUuid, }; +use bevy_mod_scripting_core::asset::CodeAsset; use std::sync::Arc; @@ -28,11 +28,10 @@ impl AssetLoader for LuaLoader { &'a self, bytes: &'a [u8], load_context: &'a mut bevy::asset::LoadContext, - ) -> bevy::asset::BoxedFuture<'a, Result<(), anyhow::Error>> { + ) -> bevy::asset::BoxedFuture<'a, Result<(), Error>> { match load_context.path().extension().map(|s| s.to_str().unwrap()) { #[cfg(all(feature = "teal", debug_assertions))] Some("tl") => { - use anyhow::anyhow; use bevy::asset::FileAssetIo; use std::fs; use std::path::PathBuf; @@ -72,10 +71,10 @@ impl AssetLoader for LuaLoader { { if !e.success() { return Box::pin(async move { - Err(anyhow!( + Err(Error::msg(format!( "Teal file `{}` has errors", load_context.path().to_str().unwrap() - )) + ))) }); } } else { @@ -96,10 +95,10 @@ impl AssetLoader for LuaLoader { { if !e.success() { return Box::pin(async move { - Err(anyhow!( + Err(Error::msg(format!( "Teal file `{}` could not be compiled!", load_context.path().to_str().unwrap() - )) + ))) }); } } else { diff --git a/src/hosts/mlua_host/docs.rs b/languages/bevy_mod_scripting_lua/src/docs.rs similarity index 98% rename from src/hosts/mlua_host/docs.rs rename to languages/bevy_mod_scripting_lua/src/docs.rs index ffc4a9bd48..297b214379 100644 --- a/src/hosts/mlua_host/docs.rs +++ b/languages/bevy_mod_scripting_lua/src/docs.rs @@ -8,7 +8,7 @@ use std::{ use bevy::asset::FileAssetIo; use tealr::TypeWalker; -use crate::{DocFragment, ScriptError}; +use bevy_mod_scripting_core::prelude::*; pub type TypeWalkerBuilder = fn(TypeWalker) -> TypeWalker; diff --git a/src/hosts/mlua_host/mod.rs b/languages/bevy_mod_scripting_lua/src/lib.rs similarity index 72% rename from src/hosts/mlua_host/mod.rs rename to languages/bevy_mod_scripting_lua/src/lib.rs index fce758fccf..6286a366d7 100644 --- a/src/hosts/mlua_host/mod.rs +++ b/languages/bevy_mod_scripting_lua/src/lib.rs @@ -1,28 +1,33 @@ -pub mod assets; -pub mod docs; - use crate::{ - api::lua::bevy::{LuaEntity, LuaWorld}, - lua::bevy::LuaScriptData, - APIProviders, ScriptData, + assets::{LuaFile, LuaLoader}, + docs::LuaDocFragment, }; -use crate::{ - script_add_synchronizer, script_hot_reload_handler, script_remove_synchronizer, - CachedScriptEventState, Recipients, Script, ScriptCollection, ScriptContexts, ScriptError, - ScriptErrorEvent, ScriptEvent, ScriptHost, -}; -use anyhow::Result; - use bevy::prelude::*; -use bevy_event_priority::AddPriorityEvent; +use bevy_mod_scripting_core::{prelude::*, systems::*}; use parking_lot::RwLock; -use tealr::mlu::mlua::{prelude::*, Function}; - use std::fmt; use std::marker::PhantomData; use std::sync::{Arc, Mutex}; +use tealr::mlu::mlua::{prelude::*, Function}; -pub use {assets::*, docs::*}; +pub mod assets; +pub mod docs; +pub mod util; +pub use tealr; +pub mod prelude { + pub use crate::{ + assets::{LuaFile, LuaLoader}, + docs::{LuaDocFragment, TypeWalkerBuilder}, + tealr::{ + self, + mlu::{ + mlua::{self, prelude::*, Value}, + TealData, + }, + }, + LuaEvent, LuaScriptHost, + }; +} pub trait LuaArg: for<'lua> ToLuaMulti<'lua> + Clone + Sync + Send + 'static {} @@ -57,48 +62,6 @@ impl ScriptEvent for LuaEvent { /// - `world` - a reference to the `bevy::ecs::World` the script lives in via [`LuaWorld`] /// - `entity` - an `Entity::to_bits` representation of the entity the script is attached to /// - `script` - an `LuaScriptData` object containing the unique id of this script -/// -/// # Examples -/// -/// You can use these variables in your APIProviders like so: -/// ``` -/// use ::std::sync::Mutex; -/// use bevy::prelude::*; -/// use bevy_mod_scripting::{*, langs::mlu::{mlua,mlua::prelude::*}}; -/// -/// #[derive(Default)] -/// pub struct LuaAPIProvider; -/// -/// /// the custom Lua api, world is provided via a global pointer, -/// /// and callbacks are defined only once at script creation -/// impl APIProvider for LuaAPIProvider { -/// type APITarget = Mutex; -/// type DocTarget = LuaDocFragment; -/// type ScriptContext = Mutex; -/// -/// fn attach_api(&mut self, ctx: &mut Self::APITarget) -> Result<(),ScriptError> { -/// // callbacks can receive any `ToLuaMulti` arguments, here '()' and -/// // return any `FromLuaMulti` arguments, here a `usize` -/// // check the Rlua documentation for more details -/// let ctx = ctx.lock().unwrap(); -/// -/// ctx.globals().set("your_callback", ctx.create_function(|ctx, ()| { -/// let globals = ctx.globals(); -/// // retrieve the world pointer -/// let world_data: usize = globals.get("world").unwrap(); -/// let world: &mut World = unsafe { &mut *(world_data as *mut World) }; -/// // retrieve script entity -/// let entity_id : u64 = globals.get("entity").unwrap(); -/// let entity : Entity = Entity::from_bits(entity_id); -/// -/// Ok(()) -/// })?)?; -/// -/// -/// Ok(()) -/// } -/// } -/// ``` pub struct LuaScriptHost { _ph: PhantomData, } @@ -157,10 +120,10 @@ impl ScriptHost for LuaScriptHost { lua.load(script) .set_name(script_data.name) - .map(|c| c.exec()) + .and_then(|c| c.exec()) .map_err(|_e| ScriptError::FailedToLoad { script: script_data.name.to_owned(), - })??; + })?; let mut lua = Mutex::new(lua); @@ -185,9 +148,9 @@ impl ScriptHost for LuaScriptHost { .map_err(|e| ScriptError::Other(e.to_string())) .and_then(|ctx| { let globals = ctx.globals(); - globals.set("world", LuaWorld::new(Arc::downgrade(&world_arc)))?; - globals.set("entity", LuaEntity::new(fd.entity))?; - globals.set::<_, LuaScriptData>("script", (&fd).into())?; + // globals.set("world", LuaWorld::new(Arc::downgrade(&world_arc)))?; + // globals.set("entity", LuaEntity::new(fd.entity))?; + // globals.set::<_, LuaScriptData>("script", (&fd).into())?; // event order is preserved, but scripts can't rely on any temporal // guarantees when it comes to other scripts callbacks, diff --git a/languages/bevy_mod_scripting_lua/src/util.rs b/languages/bevy_mod_scripting_lua/src/util.rs new file mode 100644 index 0000000000..71077cd727 --- /dev/null +++ b/languages/bevy_mod_scripting_lua/src/util.rs @@ -0,0 +1,31 @@ +/// generates path to the given script depending on build configuration. +/// (optimized builds don't have the teal compiler available) +/// +/// Current configuration will provide ".tl" paths +/// ```rust +/// use bevy_mod_scripting::lua_path; +/// assert_eq!("scripts/my_script.tl",lua_path!("my_script")) +/// ``` +#[cfg(all(feature = "teal", debug_assertions))] +#[macro_export] +macro_rules! lua_path { + ($v:literal) => { + concat!("scripts/", $v, ".tl") + }; +} + +/// generates path to the given script depending on build configuration. +/// (optimized builds don't have the teal compiler available) +/// +/// Current configuration will provide ".lua" paths +/// ```rust +/// use bevy_mod_scripting::lua_path; +/// assert_eq!("scripts/build/my_script.lua",lua_path!("my_script")) +/// ``` +#[cfg(all(feature = "teal", not(debug_assertions)))] +#[macro_export] +macro_rules! lua_path { + ($v:literal) => { + concat!("scripts/build/", $v, ".lua") + }; +} diff --git a/languages/bevy_mod_scripting_lua_derive/Cargo.toml b/languages/bevy_mod_scripting_lua_derive/Cargo.toml new file mode 100644 index 0000000000..7af6b7a945 --- /dev/null +++ b/languages/bevy_mod_scripting_lua_derive/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "bevy_mod_scripting_lua_derive" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Necessary functionality for Lua support with bevy_mod_scripting" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "rhai"] +categories = ["game-development"] +readme = "readme.md" + +[lib] +name="bevy_mod_scripting_lua_derive" +path="src/lib.rs" +proc-macro=true + +[dependencies] +bevy_mod_scripting_common = {path = "../../bevy_mod_scripting_common", version = "0.1.1"} +paste = "1.0.7" +syn = {version="1.0.57",features=["full","fold","extra-traits"]} +quote = "1.0.8" +proc-macro2 = "1.0" +convert_case = "0.5.0" +rustdoc-types = "0.11.0" +serde = { version = "1.0", features = ["derive"] } +serde_derive = "1.0.137" +indexmap = {version= "1.9.1", features= ["serde"]} diff --git a/languages/bevy_mod_scripting_lua_derive/readme.md b/languages/bevy_mod_scripting_lua_derive/readme.md new file mode 100644 index 0000000000..e058ed4f00 --- /dev/null +++ b/languages/bevy_mod_scripting_lua_derive/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_lua_derive + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/bevy_mod_scripting_derive/src/lua/derive_flags/auto_methods.rs b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/auto_methods.rs similarity index 93% rename from bevy_mod_scripting_derive/src/lua/derive_flags/auto_methods.rs rename to languages/bevy_mod_scripting_lua_derive/src/derive_flags/auto_methods.rs index b0835f71f3..e3d02905d4 100644 --- a/bevy_mod_scripting_derive/src/lua/derive_flags/auto_methods.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/auto_methods.rs @@ -1,25 +1,19 @@ use std::iter::once; +use bevy_mod_scripting_common::{ + arg::SimpleType, derive_flag::DeriveFlag, newtype::Newtype, utils::EmptyToken, +}; use proc_macro2::Span; use quote::{format_ident, quote_spanned}; use syn::{parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, LitInt, Token}; -use crate::{ - common::{arg::SimpleType, derive_flag::DeriveFlag, newtype::Newtype}, - lua::lua_method::LuaMethod, - EmptyToken, -}; +use crate::lua_method::LuaMethod; pub(crate) fn make_methods<'a>(flag: &DeriveFlag, new_type: &'a Newtype, out: &mut Vec) { - let wrapper_type = &new_type.args.wrapper_type; let wrapped_type = &new_type.args.base_type_ident; - let (ident, paren, methods) = match flag { - DeriveFlag::Methods { - ident, - paren, - methods, - } => (ident, paren, methods), + let methods = match flag { + DeriveFlag::Methods { methods, .. } => methods, _ => panic!("Expected Methods flag"), }; diff --git a/bevy_mod_scripting_derive/src/lua/derive_flags/bin_ops.rs b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/bin_ops.rs similarity index 94% rename from bevy_mod_scripting_derive/src/lua/derive_flags/bin_ops.rs rename to languages/bevy_mod_scripting_lua_derive/src/derive_flags/bin_ops.rs index fcdeb9ab45..c5f9463a12 100644 --- a/bevy_mod_scripting_derive/src/lua/derive_flags/bin_ops.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/bin_ops.rs @@ -1,17 +1,15 @@ +use bevy_mod_scripting_common::{ + arg::SimpleType, + derive_flag::DeriveFlag, + newtype::Newtype, + ops::{OpExpr, OpName, Side}, +}; use indexmap::{IndexMap, IndexSet}; use proc_macro2::TokenStream; use quote::{format_ident, quote_spanned, ToTokens}; use syn::{parse_quote_spanned, spanned::Spanned, Token}; -use crate::{ - common::{ - arg::SimpleType, - derive_flag::DeriveFlag, - newtype::Newtype, - ops::{OpExpr, OpName, Side}, - }, - lua::{lua_method::LuaMethod, LuaImplementor}, -}; +use crate::{implementor::LuaImplementor, lua_method::LuaMethod}; pub(crate) fn make_bin_ops<'a>( implementor: &mut LuaImplementor, @@ -107,7 +105,7 @@ pub(crate) fn make_bin_ops<'a>( .filter(|v| v.has_receiver_on_side(receiver_side)) .map(|op_expr| { // first of all resolve both sides of the expression - let (l_exp, r_exp) = op_expr.map_both(|arg_type, side| { + let (l_exp, r_exp) = op_expr.map_both(|arg_type, _side| { // receiver is always a lua wrapper by definition let arg_ident = arg_type .is_self() @@ -160,7 +158,7 @@ pub(crate) fn make_bin_ops<'a>( quote_spanned! {op_name.span()=> match v { #match_patterns - _ => Err(tealr::mlu::mlua::Error::RuntimeError( + _ => Err(bevy_mod_scripting_lua::tealr::mlu::mlua::Error::RuntimeError( format!("tried to `{}` `{}` with another argument on the `{}` side, but its type is not supported", stringify!(#metamethod_name), stringify!(#newtype_name), @@ -197,13 +195,13 @@ pub(crate) fn make_bin_ops<'a>( lhs_union_handlers = Default::default(); } let o = parse_quote_spanned! {ident.span()=> - fn (mlua::MetaMethod::#metamethod_name) => |ctx, (lhs,rhs) :(#lhs_arg_type,#rhs_arg_type)| { + fn (bevy_mod_scripting_lua::tealr::mlu::mlua::MetaMethod::#metamethod_name) => |ctx, (lhs,rhs) :(#lhs_arg_type,#rhs_arg_type)| { match (lhs,rhs) { // we always check implementor is on the left first #rhs_union_handlers #lhs_union_handlers - _ => Err(tealr::mlu::mlua::Error::RuntimeError( + _ => Err(bevy_mod_scripting_lua::tealr::mlu::mlua::Error::RuntimeError( format!("tried to `{}` two arguments, none of which are of type `{}` ", stringify!(#metamethod_name), stringify!(#newtype_name) diff --git a/bevy_mod_scripting_derive/src/lua/derive_flags/fields.rs b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/fields.rs similarity index 95% rename from bevy_mod_scripting_derive/src/lua/derive_flags/fields.rs rename to languages/bevy_mod_scripting_lua_derive/src/derive_flags/fields.rs index d8e7be81ac..51d0aeb9f4 100644 --- a/bevy_mod_scripting_derive/src/lua/derive_flags/fields.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/fields.rs @@ -1,10 +1,8 @@ +use bevy_mod_scripting_common::{arg::SimpleType, derive_flag::DeriveFlag, newtype::Newtype}; use quote::{format_ident, quote_spanned}; use syn::{parse_quote_spanned, spanned::Spanned}; -use crate::{ - common::{arg::SimpleType, derive_flag::DeriveFlag, newtype::Newtype}, - lua::lua_method::LuaMethod, -}; +use crate::lua_method::LuaMethod; pub(crate) fn make_fields<'a>( flag: &DeriveFlag, @@ -13,7 +11,7 @@ pub(crate) fn make_fields<'a>( ) -> Result<(), syn::Error> { let newtype_name = &new_type.args.wrapper_type; - let (ident, fields) = match flag { + let (_ident, fields) = match flag { DeriveFlag::Fields { ident, fields, .. } => (ident, fields), _ => panic!("Expected Fields flag"), }; diff --git a/bevy_mod_scripting_derive/src/lua/derive_flags/mod.rs b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/mod.rs similarity index 100% rename from bevy_mod_scripting_derive/src/lua/derive_flags/mod.rs rename to languages/bevy_mod_scripting_lua_derive/src/derive_flags/mod.rs diff --git a/bevy_mod_scripting_derive/src/lua/derive_flags/unary_ops.rs b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/unary_ops.rs similarity index 85% rename from bevy_mod_scripting_derive/src/lua/derive_flags/unary_ops.rs rename to languages/bevy_mod_scripting_lua_derive/src/derive_flags/unary_ops.rs index a6ab8770d0..551e85c111 100644 --- a/bevy_mod_scripting_derive/src/lua/derive_flags/unary_ops.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/derive_flags/unary_ops.rs @@ -1,10 +1,8 @@ +use bevy_mod_scripting_common::{derive_flag::DeriveFlag, newtype::Newtype, ops::Side}; use quote::quote_spanned; use syn::{parse_quote, parse_quote_spanned, spanned::Spanned}; -use crate::{ - common::{derive_flag::DeriveFlag, newtype::Newtype, ops::Side}, - lua::lua_method::LuaMethod, -}; +use crate::lua_method::LuaMethod; pub(crate) fn make_unary_ops<'a>( flag: &DeriveFlag, @@ -36,7 +34,7 @@ pub(crate) fn make_unary_ops<'a>( body = quote_spanned! {op.span()=>#resolved_type::new(#body)}; out.push(parse_quote_spanned! {ident.span()=> - (mlua::MetaMethod::#meta) => |_,ud,()|{ + (bevy_mod_scripting_lua::tealr::mlu::mlua::MetaMethod::#meta) => |_,ud,()|{ return Ok(#body) } }); diff --git a/bevy_mod_scripting_derive/src/lua/mod.rs b/languages/bevy_mod_scripting_lua_derive/src/implementor.rs similarity index 67% rename from bevy_mod_scripting_derive/src/lua/mod.rs rename to languages/bevy_mod_scripting_lua_derive/src/implementor.rs index a7c3971a84..868859c65f 100644 --- a/bevy_mod_scripting_derive/src/lua/mod.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/implementor.rs @@ -1,17 +1,20 @@ -pub(crate) mod derive_flags; -pub(crate) mod lua_method; - -pub(crate) use {derive_flags::*, lua_method::*}; - use indexmap::IndexSet; use proc_macro2::{Ident, Span, TokenStream}; use syn::{parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, Token}; -use crate::common::{ - attribute_to_string_lit, derive_flag::DeriveFlag, WrapperFunction, WrapperImplementor, +use bevy_mod_scripting_common::{ + derive_flag::DeriveFlag, + implementor::{WrapperFunction, WrapperImplementor}, + newtype::Newtype, + utils::attribute_to_string_lit, }; use quote::{format_ident, quote, quote_spanned}; +use crate::{ + derive_flags::{make_bin_ops, make_fields, make_methods, make_unary_ops}, + lua_method::LuaMethod, +}; + impl WrapperFunction for LuaMethod {} #[derive(Default)] @@ -24,7 +27,7 @@ impl LuaImplementor { /// Generates a union registers it, and makes sure no two identical unions exist, while removing duplicate entries in the enum /// /// The given unique type idents must be unique (i.e. come from a HashSet) - fn generate_register_union>( + pub(crate) fn generate_register_union>( &mut self, unique_type_idents: I, unique_ident: &str, @@ -41,7 +44,7 @@ impl LuaImplementor { .collect::>(); self.additional_globals.extend(quote! { - impl_tealr_any_union!(pub enum #return_arg_type = #return_arg); + bevy_script_api::impl_tealr_any_union!(pub enum #return_arg_type = #return_arg); }); } @@ -58,7 +61,7 @@ impl WrapperImplementor for LuaImplementor { fn generate_newtype_definition( &mut self, - newtype: &crate::common::newtype::Newtype, + newtype: &Newtype, ) -> std::result::Result { let newtype_name = &newtype.args.wrapper_type; let base_type = &newtype.args.base_type_ident; @@ -69,12 +72,12 @@ impl WrapperImplementor for LuaImplementor { }) { definition = quote_spanned! {newtype.span()=> #definition - bevy_mod_scripting::make_script_wrapper!(#base_type as #newtype_name with Clone); + bevy_script_api::make_script_wrapper!(#base_type as #newtype_name with Clone); }; } else { definition = quote_spanned! {newtype.span()=> #definition - bevy_mod_scripting::make_script_wrapper!(#base_type as #newtype_name); + bevy_script_api::make_script_wrapper!(#base_type as #newtype_name); }; } @@ -95,15 +98,16 @@ impl WrapperImplementor for LuaImplementor { fn generate_newtype_implementation<'a, I: Iterator>( &mut self, - newtype: &'a crate::common::newtype::Newtype, + newtype: &'a Newtype, functions: I, ) -> std::result::Result { let wrapper_type = &newtype.args.wrapper_type; let wrapped_type = &newtype.args.base_type_ident; + let tealr = quote::quote!(bevy_mod_scripting_lua::tealr); // provide documentation generation implementations let tealr_implementations = quote_spanned! {newtype.span()=> - bevy_mod_scripting::impl_tealr_type!(#wrapper_type); + bevy_script_api::impl_tealr_type!(#wrapper_type); }; // generate documentation calls on type level @@ -128,40 +132,40 @@ impl WrapperImplementor for LuaImplementor { // expose to lua let user_data_implementation = quote_spanned! {newtype.span()=> #[allow(unused_parens,unreachable_patterns,unused_variables,clippy::all)] - impl tealr::mlu::TealData for #wrapper_type { - fn add_methods<'lua, T: tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { + impl #tealr::mlu::TealData for #wrapper_type { + fn add_methods<'lua, T: #tealr::mlu::TealDataMethods<'lua, Self>>(methods: &mut T) { #type_documentator #(#methods)* } - fn add_fields<'lua, T: tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut T) { + fn add_fields<'lua, T: #tealr::mlu::TealDataFields<'lua, Self>>(fields: &mut T) { #(#fields)* } } - impl bevy_mod_scripting::LuaProxyable for #wrapped_type { - fn ref_to_lua<'lua>(self_ : bevy_mod_scripting::ScriptRef, lua: &'lua mlua::Lua) -> mlua::Result> { - <#wrapper_type as mlua::ToLua>::to_lua(#wrapper_type::new_ref(self_),lua) + impl bevy_script_api::lua::LuaProxyable for #wrapped_type { + fn ref_to_lua<'lua>(self_ : bevy_script_api::script_ref::ScriptRef, lua: &'lua #tealr::mlu::mlua::Lua) -> #tealr::mlu::mlua::Result<#tealr::mlu::mlua::Value<'lua>> { + <#wrapper_type as #tealr::mlu::mlua::ToLua>::to_lua(#wrapper_type::new_ref(self_),lua) } - fn apply_lua<'lua>(self_ : &mut bevy_mod_scripting::ScriptRef, lua: &'lua mlua::Lua, new_val: mlua::Value<'lua>) -> mlua::Result<()> { - if let mlua::Value::UserData(v) = new_val { + fn apply_lua<'lua>(self_ : &mut bevy_script_api::script_ref::ScriptRef, lua: &'lua #tealr::mlu::mlua::Lua, new_val: #tealr::mlu::mlua::Value<'lua>) -> #tealr::mlu::mlua::Result<()> { + if let #tealr::mlu::mlua::Value::UserData(v) = new_val { let other = v.borrow::<#wrapper_type>()?; let other = &other; other.apply_self_to_base(self_)?; Ok(()) } else { - Err(mlua::Error::RuntimeError( + Err(#tealr::mlu::mlua::Error::RuntimeError( "Error in assigning to custom user data".to_owned(), )) } } } - impl bevy_mod_scripting::ToLuaProxy<'_> for #wrapped_type { - fn to_lua_proxy<'lua>(self, lua: &'lua mlua::Lua) -> mlua::Result>{ - <#wrapper_type as mlua::ToLua>::to_lua(#wrapper_type::new(self),lua) + impl bevy_script_api::lua::ToLuaProxy<'_> for #wrapped_type { + fn to_lua_proxy<'lua>(self, lua: &'lua #tealr::mlu::mlua::Lua) -> #tealr::mlu::mlua::Result<#tealr::mlu::mlua::Value<'lua>>{ + <#wrapper_type as #tealr::mlu::mlua::ToLua>::to_lua(#wrapper_type::new(self),lua) } } }; @@ -176,36 +180,34 @@ impl WrapperImplementor for LuaImplementor { }) } - fn generate_derive_flag_functions< - 'a, - I: Iterator, - >( + fn generate_derive_flag_functions<'a, I: Iterator>( &mut self, - new_type: &'a crate::common::newtype::Newtype, + new_type: &'a Newtype, mut derive_flags: I, ) -> Result, syn::Error> { let mut out: Vec = Default::default(); let wrapper_type = &new_type.args.wrapper_type; let wrapped_type = &new_type.args.base_type_ident; + let tealr = quote::quote!(bevy_mod_scripting_lua::tealr); derive_flags.try_for_each(|v| { match v { DeriveFlag::Debug{ident} => out.push(parse_quote_spanned!{ident.span()=> - (mlua::MetaMethod::ToString) => |_,s,()| Ok(format!("{:?}",s)) + (#tealr::mlu::mlua::MetaMethod::ToString) => |_,s,()| Ok(format!("{:?}",s)) }), DeriveFlag::Display{ident} => out.push(parse_quote_spanned!{ident.span()=> - (mlua::MetaMethod::ToString) => |_,s,()| Ok(format!("{}",s)) + (#tealr::mlu::mlua::MetaMethod::ToString) => |_,s,()| Ok(format!("{}",s)) }), DeriveFlag::Clone{ident} => { self.additional_globals.extend( quote_spanned!{ident.span()=> - impl bevy_mod_scripting::FromLuaProxy<'_> for #wrapped_type { - fn from_lua_proxy<'lua>(lua_value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result { - if let mlua::Value::UserData(ud) = lua_value{ + impl bevy_script_api::lua::FromLuaProxy<'_> for #wrapped_type { + fn from_lua_proxy<'lua>(lua_value: #tealr::mlu::mlua::Value<'lua>, _: &'lua #tealr::mlu::mlua::Lua) -> #tealr::mlu::mlua::Result { + if let #tealr::mlu::mlua::Value::UserData(ud) = lua_value{ let wrapper = ud.borrow::<#wrapper_type>()?; Ok(std::ops::Deref::deref(&wrapper).inner()?) } else { - Err(mlua::Error::FromLuaConversionError{ + Err(#tealr::mlu::mlua::Error::FromLuaConversionError{ from: "", to: "", message: None @@ -238,12 +240,21 @@ impl WrapperImplementor for LuaImplementor { fn generate_newtype_functions( &mut self, - new_type: &crate::common::newtype::Newtype, + new_type: &Newtype, ) -> Result, syn::Error> { - Ok(new_type - .additional_lua_functions - .as_ref() - .map(|v| v.functions.iter().cloned().collect()) - .unwrap_or_default()) + let lua_block = new_type + .impl_blocks + .iter() + .find(|block| block.label == "lua"); + + if let Some(block) = lua_block { + let functions = &block.functions; + let tokens: Punctuated = + parse_quote_spanned!(block.span()=>#functions); + + Ok(tokens.into_iter().collect()) + } else { + Ok(Default::default()) + } } } diff --git a/languages/bevy_mod_scripting_lua_derive/src/lib.rs b/languages/bevy_mod_scripting_lua_derive/src/lib.rs new file mode 100644 index 0000000000..b96ac06ee3 --- /dev/null +++ b/languages/bevy_mod_scripting_lua_derive/src/lib.rs @@ -0,0 +1,20 @@ +use bevy_mod_scripting_common::{implementor::WrapperImplementor, newtype::Newtype}; +use implementor::LuaImplementor; +use proc_macro::TokenStream; +use syn::parse_macro_input; + +pub(crate) mod derive_flags; +pub(crate) mod implementor; +pub(crate) mod lua_method; + +#[proc_macro] +pub fn impl_lua_newtype(tokens: TokenStream) -> TokenStream { + let newtype = parse_macro_input!(tokens as Newtype); + let mut implementor = LuaImplementor::default(); + + implementor + .generate(newtype) + .map_err(|e| e.to_compile_error()) + .unwrap_or_else(core::convert::identity) + .into() +} diff --git a/bevy_mod_scripting_derive/src/lua/lua_method.rs b/languages/bevy_mod_scripting_lua_derive/src/lua_method.rs similarity index 84% rename from bevy_mod_scripting_derive/src/lua/lua_method.rs rename to languages/bevy_mod_scripting_lua_derive/src/lua_method.rs index 4eb99c60b0..3d9110e636 100644 --- a/bevy_mod_scripting_derive/src/lua/lua_method.rs +++ b/languages/bevy_mod_scripting_lua_derive/src/lua_method.rs @@ -1,18 +1,14 @@ -use convert_case::{Case, Casing}; +use bevy_mod_scripting_common::utils::{attribute_to_string_lit, EmptyToken}; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote_spanned, ToTokens}; use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned, - token::{Brace, Paren}, + token::Paren, *, }; -use crate::EmptyToken; - -use crate::utils::attribute_to_string_lit; - #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct MethodMacroArg { pub ident: Ident, @@ -148,7 +144,6 @@ impl ToTokens for LuaMethodType { } } -#[derive(Clone, Debug)] pub(crate) struct LuaClosure { arrow: Token![=>], expr: ExprClosure, @@ -174,45 +169,18 @@ impl LuaClosure { impl ToTokens for LuaClosure { fn to_tokens(&self, tokens: &mut TokenStream) { + let arrow = &self.arrow; let expr = &self.expr; tokens.extend(quote::quote! { - => #expr + #arrow #expr }); } } -#[derive(Clone, Debug)] -pub(crate) struct Test { - pub brace: Brace, - pub ts: TokenStream, -} - -#[allow(clippy::eval_order_dependence)] -impl Parse for Test { - fn parse(input: ParseStream) -> Result { - let f; - Ok(Self { - brace: braced!(f in input), - ts: f.parse()?, - }) - } -} - -impl ToTokens for Test { - fn to_tokens(&self, tokens: &mut TokenStream) { - let ts = &self.ts; - tokens.extend(quote::quote! { - {#ts} - }) - } -} - -#[derive(Clone, Debug)] pub(crate) struct LuaMethod { pub docstring: Vec, pub method_type: LuaMethodType, pub closure: LuaClosure, - pub test: Option, } impl Parse for LuaMethod { @@ -222,12 +190,6 @@ impl Parse for LuaMethod { docstring, method_type: input.parse()?, closure: input.parse()?, - test: if input.peek(Token![=>]) { - input.parse::]>()?; - Some(input.parse()?) - } else { - None - }, }) } } @@ -238,27 +200,13 @@ impl ToTokens for LuaMethod { let mt = &self.method_type; let closure = &self.closure; - let test = self.test.as_ref().map(|t| { - quote::quote! { - => #t - } - }); tokens.extend(quote::quote! { - #ds #mt #closure #test + #ds #mt #closure }) } } impl LuaMethod { - pub fn gen_tests(&self, newtype_name: &str) -> Option { - self.test.as_ref().map(|v| { - let fun = v.ts.clone(); - let test_ident = Ident::new(&newtype_name.to_case(Case::Snake), Span::call_site()); - - fun.into_token_stream() - }) - } - /// Generates the function call expression corresponding to the mlua /// UserData method which implements the given method or field /// diff --git a/languages/bevy_mod_scripting_rhai/Cargo.toml b/languages/bevy_mod_scripting_rhai/Cargo.toml new file mode 100644 index 0000000000..967774b432 --- /dev/null +++ b/languages/bevy_mod_scripting_rhai/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "bevy_mod_scripting_rhai" +version = "0.1.1" +authors = ["Maksymilian Mozolewski "] +edition = "2021" +license = "MIT" +description = "Necessary functionality for Rhai support with bevy_mod_scripting" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "rhai"] +categories = ["game-development"] +readme = "readme.md" + +[lib] +name="bevy_mod_scripting_rhai" +path="src/lib.rs" + +[dependencies] +bevy= { version = "0.8.0", default-features = false} +rhai = { version = "1.8.0", features = ["sync"] } +bevy_mod_scripting_core = {path="../../bevy_mod_scripting_core", version="0.1.1"} \ No newline at end of file diff --git a/languages/bevy_mod_scripting_rhai/readme.md b/languages/bevy_mod_scripting_rhai/readme.md new file mode 100644 index 0000000000..f53e843c70 --- /dev/null +++ b/languages/bevy_mod_scripting_rhai/readme.md @@ -0,0 +1,3 @@ +# bevy_mod_scripting_rhai + +This crate is a part of the ["bevy_mod_scripting" workspace](https://github.com/makspll/bevy_mod_scripting). \ No newline at end of file diff --git a/src/hosts/rhai_host/assets.rs b/languages/bevy_mod_scripting_rhai/src/assets.rs similarity index 87% rename from src/hosts/rhai_host/assets.rs rename to languages/bevy_mod_scripting_rhai/src/assets.rs index e88bb52ca5..ef90336adc 100644 --- a/src/hosts/rhai_host/assets.rs +++ b/languages/bevy_mod_scripting_rhai/src/assets.rs @@ -1,8 +1,9 @@ -use crate::CodeAsset; use bevy::{ + asset::Error, asset::{AssetLoader, LoadedAsset}, reflect::TypeUuid, }; +use bevy_mod_scripting_core::prelude::*; use std::sync::Arc; #[derive(Debug, TypeUuid)] @@ -27,7 +28,7 @@ impl AssetLoader for RhaiLoader { &'a self, bytes: &'a [u8], load_context: &'a mut bevy::asset::LoadContext, - ) -> bevy::asset::BoxedFuture<'a, Result<(), anyhow::Error>> { + ) -> bevy::asset::BoxedFuture<'a, Result<(), Error>> { load_context.set_default_asset(LoadedAsset::new(RhaiFile { bytes: bytes.into(), })); diff --git a/src/hosts/rhai_host/docs.rs b/languages/bevy_mod_scripting_rhai/src/docs.rs similarity index 83% rename from src/hosts/rhai_host/docs.rs rename to languages/bevy_mod_scripting_rhai/src/docs.rs index 45541f9b6c..dc33989038 100644 --- a/src/hosts/rhai_host/docs.rs +++ b/languages/bevy_mod_scripting_rhai/src/docs.rs @@ -1,4 +1,4 @@ -use crate::{DocFragment, ScriptError}; +use bevy_mod_scripting_core::prelude::*; pub struct RhaiDocFragment; diff --git a/src/hosts/rhai_host/mod.rs b/languages/bevy_mod_scripting_rhai/src/lib.rs similarity index 92% rename from src/hosts/rhai_host/mod.rs rename to languages/bevy_mod_scripting_rhai/src/lib.rs index e17e868dd7..3ebdf2e7ae 100644 --- a/src/hosts/rhai_host/mod.rs +++ b/languages/bevy_mod_scripting_rhai/src/lib.rs @@ -1,19 +1,23 @@ -pub mod assets; -mod docs; - use crate::{ - script_add_synchronizer, script_hot_reload_handler, script_remove_synchronizer, APIProviders, - CachedScriptEventState, Recipients, Script, ScriptCollection, ScriptContexts, ScriptData, - ScriptError, ScriptErrorEvent, ScriptEvent, ScriptHost, -}; -use bevy::prelude::{ - error, AddAsset, Mut, ParallelSystemDescriptorCoercion, ResMut, SystemSet, World, + assets::{RhaiFile, RhaiLoader}, + docs::RhaiDocFragment, }; -use bevy_event_priority::AddPriorityEvent; +use bevy::prelude::*; +use bevy_mod_scripting_core::{prelude::*, systems::*}; use rhai::*; use std::marker::PhantomData; -pub use {assets::*, docs::*}; +pub mod assets; +pub mod docs; +pub use rhai; +pub mod prelude { + pub use crate::{ + assets::{RhaiFile, RhaiLoader}, + docs::RhaiDocFragment, + RhaiContext, RhaiEvent, RhaiScriptHost, + }; + pub use rhai; +} pub struct RhaiScriptHost { pub engine: Engine, diff --git a/makefile b/makefile index 6bf68f9c1a..ccedaba4bb 100644 --- a/makefile +++ b/makefile @@ -54,25 +54,25 @@ generate_api: --json "../target/doc/bevy.json" \ --json "../target/doc/glam.json" \ --config "../api_gen_config.toml" ${FLAGS} \ - > ../src/api/generated.rs + > ../bevy_script_api/src/generated.rs make_json_files: - rustup run nightly cargo rustdoc -p bevy_asset@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_ecs@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_pbr@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_render@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_math@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_transform@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_sprite@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_ui@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_animation@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_core@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_core_pipeline@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_gltf@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_hierarchy@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_text@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_time@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_utils@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy_reflect@0.8.0 -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p glam -- -Zunstable-options --output-format json && \ - rustup run nightly cargo rustdoc -p bevy@0.8.0 -- -Zunstable-options --output-format json + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_asset@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_ecs@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_pbr@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_render@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_math@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_transform@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_sprite@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_ui@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_animation@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_core@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_core_pipeline@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_gltf@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_hierarchy@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_text@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_time@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_utils@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy_reflect@0.8.0 -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p glam -- -Zunstable-options --output-format json && \ + rustup run nightly-2022-07-01 cargo rustdoc -p bevy@0.8.0 -- -Zunstable-options --output-format json diff --git a/readme.md b/readme.md index 712e400810..0c942cf7d7 100644 --- a/readme.md +++ b/readme.md @@ -103,10 +103,11 @@ Any types implementing the `mlua::ToLua` trait can be used. ``` rust use bevy::prelude::*; -use bevy_mod_scripting::{prelude::*,events::*,langs::mlu::{mlua,mlua::prelude::*}}; +use bevy_mod_scripting::prelude::*; // event callback generator for lua +#[cfg(feature = "lua")] pub fn trigger_on_update_lua(mut w: PriorityEventWriter>) { let event = LuaEvent::<()> { hook_name: "on_update".to_string(), @@ -124,13 +125,15 @@ Rhai supports any rust types implementing FuncArgs as function arguments. ``` rust use bevy::prelude::*; -use bevy_mod_scripting::{prelude::*,langs::rhai::FuncArgs}; +use bevy_mod_scripting::prelude::*; +#[cfg(feature = "rhai")] #[derive(Clone)] pub struct MyRhaiArgStruct { // ... } +#[cfg(feature = "rhai")] impl FuncArgs for MyRhaiArgStruct { fn parse>(self, _args: &mut ARGS) { // ... @@ -139,6 +142,7 @@ impl FuncArgs for MyRhaiArgStruct { // event callback generator for rhai // rhai event arguments can be any rust type implementing FuncArgs +#[cfg(feature = "rhai")] pub fn trigger_on_update_rhai(mut w: PriorityEventWriter>) { let event = RhaiEvent { hook_name: "on_update".to_string(), @@ -165,6 +169,7 @@ use bevy_mod_scripting::prelude::*; // An example of a startup system which loads the lua script "console_integration.lua" // placed in "assets/scripts/" and attaches it to a new entity +#[cfg(feature = "lua")] pub fn load_a_script( server: Res, mut commands: Commands, @@ -188,13 +193,15 @@ To expose an API to your scripts, implement the APIProvider trait. To register t ``` rust use ::std::sync::Mutex; -use bevy_mod_scripting::{prelude::*,langs::{mlu::mlua::prelude::*,rhai::*}}; +use bevy_mod_scripting::prelude::*; +#[cfg(feature = "lua")] #[derive(Default)] pub struct LuaAPI; /// the custom Lua api, world is provided via a global pointer, /// and callbacks are defined only once at script creation +#[cfg(feature = "lua")] impl APIProvider for LuaAPI { type APITarget = Mutex; type DocTarget = LuaDocFragment; @@ -208,9 +215,11 @@ impl APIProvider for LuaAPI { } } +#[cfg(feature = "rhai")] #[derive(Default)] pub struct RhaiAPI {} +#[cfg(feature = "rhai")] impl APIProvider for RhaiAPI { type APITarget = Engine; type DocTarget = RhaiDocFragment; @@ -245,6 +254,7 @@ Documentation features are exposed at runtime via the `update_documentation` bui use bevy::prelude::*; use bevy_mod_scripting::prelude::*; +#[cfg(feature = "lua")] fn main() -> std::io::Result<()> { let mut app = App::new(); diff --git a/src/api/lua.md b/src/api/lua.md deleted file mode 100644 index 83804015f5..0000000000 --- a/src/api/lua.md +++ /dev/null @@ -1,96 +0,0 @@ -# Lua Api - - -# Supported Bevy Types - - -## bevy_animation --[ ] EntityPath --[ ] KeyFrames --[ ] VariableCurve - -## bevy_asset --[ ] Handle --[ ] HandleUntyped - -## bevy_core --[ ] Time - -## bevy_ecs --[ ] Entity --[ ] World - -## bevy_hierarchy --[ ] Parent --[ ] Children - -## bevy_input --[ ] Input --[ ] KeyboardInput --[ ] KeyCode --[ ] Gamepad --[ ] GamepadButton --[ ] Gamepads --[ ] GamepadEvent --[ ] GamepadButtonType --[ ] GamepadAxisType --[ ] GamepadAxis --[ ] GamepadSettings --[ ] ButtonSettings --[ ] AxisSettings --[ ] GamepadEventType --[ ] MouseButton --[ ] MouseButtonInput --[ ] MouseWheel --[ ] MouseMotion --[ ] CursorMoved --[ ] Touches --[ ] TouchInput --[ ] FileDragAndDrop - -## bevy_math --[ ] BVec2 --[ ] BVec3 --[ ] BVec4 --[ ] EulerRot --[x] IVec2 --[x] IVec3 --[x] IVec4 --[ ] Mat3 --[ ] Mat4 --[ ] Quat --[x] UVec2 --[x] UVec3 --[x] UVec4 --[x] Vec2 --[x] Vec3 --[x] Vec4 - -## bevy_render --[ ] Camera --[ ] Color --[ ] Image - -## bevy_scene - -## bevy_sprite --[ ] Sprite --[ ] Mesh2dHandle - -## bevy_text --[ ] Text --[ ] Font --[ ] HorizontalAlign --[ ] TextAlignment --[ ] TextStyle --[ ] VerticalAlign - -## bevy_transform --[ ] TransformBundle --[ ] Transform --[ ] GlobalTransform - -## bevy_ui --[ ] Windows --[ ] Window --[ ] ReceivedCharacter diff --git a/src/api/mod.rs b/src/api/mod.rs deleted file mode 100644 index 7624496b44..0000000000 --- a/src/api/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate bevy; - -pub mod generated; -pub mod lua; -pub mod script_ref; -pub mod sub_reflect; -pub mod wrappers; - -pub use {lua::*, script_ref::*, sub_reflect::*, wrappers::*}; diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index e1eb66349c..0000000000 --- a/src/error.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::{borrow::Cow, fmt::Debug}; -use tealr::mlu::mlua; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum ScriptError { - #[error("Runtime error in script `{script}` {msg}")] - RuntimeError { script: String, msg: String }, - #[error("Failed to load script asset for `{script}`")] - FailedToLoad { script: String }, - #[error("Syntax error for script `{script}` {msg}")] - SyntaxError { script: String, msg: String }, - #[error("Callback method `{callback}` invalid for script `{script}` {msg}")] - InvalidCallback { - script: String, - callback: String, - msg: String, - }, - #[error("Failed to attach API for script `{script}` {msg}")] - FailedToAttachAPI { script: String, msg: String }, - #[error("Failed to generate documentation `{0}`")] - DocGenError(String), - #[error("{0}")] - Other(String), -} - -#[derive(Error, Debug)] -pub enum ReflectionError { - #[error("Base reference `{base}` is invalid. {reason}")] - InvalidBaseReference { base: String, reason: String }, - #[error("Insuficient provenance error while accessing `{path}`. {msg}")] - InsufficientProvenance { path: String, msg: String }, - #[error("Invalid reflection path: `{path}`. {msg}")] - InvalidReflectionPath { path: String, msg: String }, - #[error("Cannot downcast from `{from}` to `{to}`")] - CannotDowncast { - from: Cow<'static, str>, - to: Cow<'static, str>, - }, - #[error("{0}")] - Other(String), -} - -// impl Into for ReflectionError { -// fn into(self) -> mlua::Error { -// mlua::Error::RuntimeError(self.to_string()) -// } -// } - -impl From for mlua::Error { - fn from(e: ReflectionError) -> Self { - Self::RuntimeError(e.to_string()) - } -} - -impl From for ScriptError { - fn from(e: mlua::Error) -> Self { - Self::Other(e.to_string()) - } -} diff --git a/src/lib.rs b/src/lib.rs index c585872658..433ff02bd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,247 +1,40 @@ #![doc=include_str!("../readme.md")] -use ::std::any::TypeId; -use bevy::{ - ecs::schedule::IntoRunCriteria, - prelude::*, - reflect::{FromType, GetTypeRegistration, TypeRegistryArc}, -}; - -pub mod error; -pub mod hosts; -pub mod util; -pub mod langs { - pub use {rhai, tealr::mlu}; -} -pub mod api; - -pub use bevy_event_priority as events; -pub use {api::*, error::*, hosts::*, langs::*, util::*}; - -pub mod prelude { - // general - pub use { - crate::hosts::{ - APIProvider, APIProviders, CodeAsset, Recipients, Script, ScriptCollection, - ScriptContexts, ScriptData, ScriptEvent, ScriptHost, - }, - crate::{ - AddScriptApiProvider, AddScriptHost, AddScriptHostHandler, GenDocumentation, - ReflectPathElem, ScriptError, ScriptErrorEvent, ScriptRef, ScriptingPlugin, ValueIndex, - }, - bevy_event_priority::{ - AddPriorityEvent, PriorityEvent, PriorityEventReader, PriorityEventWriter, - PriorityEvents, PriorityIterator, - }, - bevy_mod_scripting_derive::impl_script_newtype, - }; - - // lua - pub use crate::{ - langs::mlu::mlua::Lua, FromLuaProxy, LuaDocFragment, LuaEvent, LuaFile, LuaProxyable, - LuaScriptHost, ReflectLuaProxyable, RegisterForeignLuaType, ToLuaProxy, - }; - - // rhai - pub use crate::{langs::rhai::Engine, RhaiContext, RhaiDocFragment, RhaiEvent, RhaiFile}; -} - -#[derive(Default)] -/// Bevy plugin enabling run-time scripting -pub struct ScriptingPlugin; - -impl Plugin for ScriptingPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - app.add_event::(); - } -} - -/// A trait allowing to register the [`LuaProxyable`] trait with the type registry for foreign types -/// -/// If you have access to the type you should prefer to use `#[reflect(LuaProxyable)]` instead. -/// This is exactly equivalent. -pub trait RegisterForeignLuaType { - /// Register an instance of `ReflecLuaProxyable` type data on this type's registration, - /// if a registration does not yet exist, creates one. - fn register_foreign_lua_type( - &mut self, - ) -> &mut Self; -} - -impl RegisterForeignLuaType for App { - fn register_foreign_lua_type( - &mut self, - ) -> &mut Self { - { - let registry = self.world.resource_mut::(); - let mut registry = registry.write(); - - let user_data = >::from_type(); - - if let Some(registration) = registry.get_mut(TypeId::of::()) { - registration.insert(user_data) - } else { - let mut registration = T::get_type_registration(); - registration.insert(user_data); - registry.add_registration(registration); - } - } - - self - } -} - -/// An error coming from a script -#[derive(Debug)] -pub struct ScriptErrorEvent { - pub err: ScriptError, -} - -pub trait GenDocumentation { - fn update_documentation(&mut self) -> &mut Self; +pub mod core { + pub use bevy_mod_scripting_core::*; } -impl GenDocumentation for App { - /// Updates/Generates documentation and any other artifacts required for script API's. Disabled in optimized builds unless `doc_always` feature is enabled. - fn update_documentation(&mut self) -> &mut Self { - #[cfg(any(debug_assertions, feature = "doc_always"))] - { - info!("Generating documentation"); - let w = &mut self.world; - let providers: &APIProviders = w.resource(); - if let Err(e) = providers.gen_all() { - error!("{}", e); - } - info!("Documentation generated"); - } +#[cfg(feature = "lua")] +pub mod lua { + pub use bevy_mod_scripting_lua::*; - self + #[cfg(feature = "lua_script_api")] + pub mod api { + pub use bevy_script_api::lua::*; } } -/// Trait for app builder notation -pub trait AddScriptHost { - /// registers the given script host with your app - fn add_script_host(&mut self, stage: S) -> &mut Self; -} +#[cfg(feature = "rhai")] +pub mod rhai { + pub use bevy_mod_scripting_rhai::*; -impl AddScriptHost for App { - fn add_script_host(&mut self, stage: S) -> &mut Self { - T::register_with_app(self, stage); - self.init_resource::(); - self + #[cfg(feature = "rhai_script_api")] + pub mod api { + // pub use bevy_script_api::rhai::*; } } -pub trait AddScriptApiProvider { - fn add_api_provider( - &mut self, - provider: Box< - dyn APIProvider< - APITarget = T::APITarget, - DocTarget = T::DocTarget, - ScriptContext = T::ScriptContext, - >, - >, - ) -> &mut Self; +#[cfg(any(feature = "lua_script_api", feature = "rhai_script_api"))] +pub mod api { + pub use bevy_script_api::*; } -impl AddScriptApiProvider for App { - fn add_api_provider( - &mut self, - provider: Box< - dyn APIProvider< - APITarget = T::APITarget, - DocTarget = T::DocTarget, - ScriptContext = T::ScriptContext, - >, - >, - ) -> &mut Self { - provider.register_with_app(self); - let w = &mut self.world; - let providers: &mut APIProviders = &mut w.resource_mut(); - providers.providers.push(provider); - self - } -} - -pub trait AddScriptHostHandler { - /// Enables this script host to handle events with priorities in the range [0,min_prio] (inclusive), - /// during the runtime of the given stage. - /// - /// Think of handler stages as a way to run certain types of events at various points in your engine. - /// A good example of this is Unity [game loop's](https://docs.unity3d.com/Manual/ExecutionOrder.html) `onUpdate` and `onFixedUpdate`. - /// FixedUpdate runs *before* any physics while Update runs after physics and input events. - /// - /// A similar setup can be achieved by using a separate stage before and after your physics, - /// then assigning event priorities such that your events are forced to run at a particular stage, for example: - /// - /// PrePhysics: min_prio = 1 - /// PostPhysics: min_prio = 4 - /// - /// | Priority | Handler | Event | - /// | -------- | ----------- | ------------ | - /// | 0 | PrePhysics | Start | - /// | 1 | PrePhysics | FixedUpdate | - /// | 2 | PostPhysics | OnCollision | - /// | 3 | PostPhysics | OnMouse | - /// | 4 | PostPhysics | Update | - /// - /// The *frequency* of running these events, is controlled by your systems, if the event is not emitted, it cannot not handled. - /// Of course there is nothing stopping your from emitting a single event type at varying priorities. - fn add_script_handler_stage( - &mut self, - stage: S, - ) -> &mut Self; - - /// Like `add_script_handler_stage` but with additional run criteria - fn add_script_handler_stage_with_criteria< - T: ScriptHost, - S: StageLabel, - M, - C: IntoRunCriteria, - const MAX: u32, - const MIN: u32, - >( - &mut self, - stage: S, - criteria: C, - ) -> &mut Self; -} +pub mod prelude { + pub use bevy_mod_scripting_core::prelude::*; -impl AddScriptHostHandler for App { - fn add_script_handler_stage( - &mut self, - stage: S, - ) -> &mut Self { - self.add_system_to_stage( - stage, - script_event_handler:: - .exclusive_system() - .at_end(), - ); - self - } + #[cfg(feature = "lua")] + pub use bevy_mod_scripting_lua::prelude::*; - fn add_script_handler_stage_with_criteria< - T: ScriptHost, - S: StageLabel, - M, - C: IntoRunCriteria, - const MAX: u32, - const MIN: u32, - >( - &mut self, - stage: S, - criteria: C, - ) -> &mut Self { - self.add_system_to_stage( - stage, - script_event_handler:: - .exclusive_system() - .at_end() - .with_run_criteria(criteria), - ); - self - } + #[cfg(feature = "rhai")] + pub use bevy_mod_scripting_rhai::prelude::*; }