scripting: fix lua scripting (#13), create an example for it
ci/woodpecker/push/debug Pipeline failed
Details
ci/woodpecker/push/debug Pipeline failed
Details
This commit is contained in:
parent
1b08482ef7
commit
29c68abbbb
|
@ -1803,6 +1803,18 @@ dependencies = [
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lua-scripting"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-std",
|
||||||
|
"fps_counter",
|
||||||
|
"lyra-engine",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lyra-ecs"
|
name = "lyra-ecs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1927,6 +1939,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-math",
|
"lyra-math",
|
||||||
|
"lyra-reflect",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1934,6 +1947,7 @@ name = "lyra-scripting"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"atomic_refcell",
|
||||||
"elua",
|
"elua",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.0",
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
|
@ -1941,6 +1955,7 @@ dependencies = [
|
||||||
"lyra-reflect",
|
"lyra-reflect",
|
||||||
"lyra-resource",
|
"lyra-resource",
|
||||||
"lyra-scripting-derive",
|
"lyra-scripting-derive",
|
||||||
|
"paste",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -1950,6 +1965,7 @@ dependencies = [
|
||||||
name = "lyra-scripting-derive"
|
name = "lyra-scripting-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"paste",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.51",
|
"syn 2.0.51",
|
||||||
|
|
|
@ -10,7 +10,14 @@ members = [
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-reflect",
|
"lyra-reflect",
|
||||||
"lyra-scripting",
|
"lyra-scripting",
|
||||||
"lyra-game", "lyra-math", "lyra-scene", "examples/many-lights", "examples/fixed-timestep-rotating-model"]
|
"lyra-game",
|
||||||
|
"lyra-math",
|
||||||
|
"lyra-scene",
|
||||||
|
|
||||||
|
"examples/many-lights",
|
||||||
|
"examples/fixed-timestep-rotating-model",
|
||||||
|
"examples/lua-scripting"
|
||||||
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
scripting = ["dep:lyra-scripting"]
|
scripting = ["dep:lyra-scripting"]
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
[package]
|
||||||
|
name = "lua-scripting"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lyra-engine = { path = "../../", features = ["tracy", "lua_scripting"] }
|
||||||
|
anyhow = "1.0.75"
|
||||||
|
async-std = "1.12.0"
|
||||||
|
tracing = "0.1.37"
|
||||||
|
rand = "0.8.5"
|
||||||
|
fps_counter = "3.0.0"
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
linker = "/usr/bin/clang"
|
||||||
|
rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
|
@ -0,0 +1,59 @@
|
||||||
|
---Return the userdata's name from its metatable
|
||||||
|
---@param val userdata
|
||||||
|
---@return string
|
||||||
|
function udname(val)
|
||||||
|
return getmetatable(val).__name
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_init()
|
||||||
|
local cube = world:request_res("../assets/cube-texture-embedded.gltf")
|
||||||
|
print("Loaded textured cube (" .. udname(cube) .. ")")
|
||||||
|
|
||||||
|
cube:wait_until_loaded()
|
||||||
|
local scenes = cube:scenes()
|
||||||
|
local cube_scene = scenes[1]
|
||||||
|
|
||||||
|
local pos = Transform.from_translation(Vec3.new(0, 0, -8.0))
|
||||||
|
|
||||||
|
local e = world:spawn(pos, cube_scene)
|
||||||
|
print("spawned entity " .. tostring(e))
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ function on_first()
|
||||||
|
print("Lua's first function was called")
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_pre_update()
|
||||||
|
print("Lua's pre-update function was called")
|
||||||
|
end ]]
|
||||||
|
|
||||||
|
function on_update()
|
||||||
|
--[[ ---@type number
|
||||||
|
local dt = world:resource(DeltaTime)
|
||||||
|
local act = world:resource(ActionHandler)
|
||||||
|
---@type number
|
||||||
|
local move_objs = act:get_axis("ObjectsMoveUpDown")
|
||||||
|
|
||||||
|
world:view(function (t)
|
||||||
|
if move_objs ~= nil then
|
||||||
|
t:translate(0, move_objs * 0.35 * dt, 0)
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
end, Transform) ]]
|
||||||
|
|
||||||
|
---@type number
|
||||||
|
local dt = world:resource(DeltaTime)
|
||||||
|
|
||||||
|
world:view(function (t)
|
||||||
|
t:translate(0, 0.15 * dt, 0)
|
||||||
|
return t
|
||||||
|
end, Transform)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[ function on_post_update()
|
||||||
|
print("Lua's post-update function was called")
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_last()
|
||||||
|
print("Lua's last function was called")
|
||||||
|
end ]]
|
|
@ -0,0 +1,151 @@
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
use lyra_engine::{
|
||||||
|
assets::{gltf::Gltf, ResourceManager}, ecs::{
|
||||||
|
query::{Res, ResMut, View},
|
||||||
|
system::{BatchedSystem, Criteria, CriteriaSchedule, IntoSystem},
|
||||||
|
World,
|
||||||
|
}, game::Game, input::{
|
||||||
|
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||||
|
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
||||||
|
}, lua::{LuaScript, LuaScriptingPlugin}, math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{
|
||||||
|
CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform,
|
||||||
|
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN,
|
||||||
|
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
|
||||||
|
}, DeltaTime, Script, ScriptList
|
||||||
|
};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() {
|
||||||
|
let action_handler_plugin = |game: &mut Game| {
|
||||||
|
let action_handler = ActionHandler::builder()
|
||||||
|
.add_layout(LayoutId::from(0))
|
||||||
|
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||||
|
.add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
||||||
|
.add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis))
|
||||||
|
.add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
||||||
|
.add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis))
|
||||||
|
.add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis))
|
||||||
|
.add_action("Debug", Action::new(ActionKind::Button))
|
||||||
|
.add_mapping(
|
||||||
|
ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0))
|
||||||
|
.bind(
|
||||||
|
ACTLBL_MOVE_FORWARD_BACKWARD,
|
||||||
|
&[
|
||||||
|
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
ACTLBL_MOVE_LEFT_RIGHT,
|
||||||
|
&[
|
||||||
|
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
ACTLBL_MOVE_UP_DOWN,
|
||||||
|
&[
|
||||||
|
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
ACTLBL_LOOK_LEFT_RIGHT,
|
||||||
|
&[
|
||||||
|
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
|
||||||
|
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
ACTLBL_LOOK_UP_DOWN,
|
||||||
|
&[
|
||||||
|
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
|
||||||
|
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
ACTLBL_LOOK_ROLL,
|
||||||
|
&[
|
||||||
|
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
||||||
|
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.bind(
|
||||||
|
"Debug",
|
||||||
|
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
)
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
let world = game.world_mut();
|
||||||
|
world.add_resource(action_handler);
|
||||||
|
game.with_plugin(InputActionPlugin);
|
||||||
|
};
|
||||||
|
|
||||||
|
Game::initialize()
|
||||||
|
.await
|
||||||
|
.with_plugin(lyra_engine::DefaultPlugins)
|
||||||
|
.with_plugin(setup_scene_plugin)
|
||||||
|
.with_plugin(action_handler_plugin)
|
||||||
|
.with_plugin(setup_script_plugin)
|
||||||
|
//.with_plugin(camera_debug_plugin)
|
||||||
|
.with_plugin(FreeFlyCameraPlugin)
|
||||||
|
.run()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_scene_plugin(game: &mut Game) {
|
||||||
|
let world = game.world_mut();
|
||||||
|
let resman = world.get_resource_mut::<ResourceManager>();
|
||||||
|
let camera_gltf = resman
|
||||||
|
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
camera_gltf.wait_recurse_dependencies_load();
|
||||||
|
let camera_mesh = &camera_gltf.data_ref().unwrap().scenes[0];
|
||||||
|
drop(resman);
|
||||||
|
|
||||||
|
world.spawn((
|
||||||
|
camera_mesh.clone(),
|
||||||
|
WorldTransform::default(),
|
||||||
|
Transform::from_xyz(0.0, -5.0, -2.0),
|
||||||
|
));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0);
|
||||||
|
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
||||||
|
light_tran.rotate_x(math::Angle::Degrees(-45.0));
|
||||||
|
light_tran.rotate_y(math::Angle::Degrees(25.0));
|
||||||
|
world.spawn((
|
||||||
|
DirectionalLight {
|
||||||
|
enabled: true,
|
||||||
|
color: Vec3::ONE,
|
||||||
|
intensity: 0.15, //..Default::default()
|
||||||
|
},
|
||||||
|
light_tran,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut camera = CameraComponent::new_3d();
|
||||||
|
camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5);
|
||||||
|
world.spawn((camera, FreeFlyCamera::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_script_plugin(game: &mut Game) {
|
||||||
|
game.with_plugin(LuaScriptingPlugin);
|
||||||
|
|
||||||
|
let world = game.world_mut();
|
||||||
|
let res_man = world.get_resource_mut::<ResourceManager>();
|
||||||
|
let script = res_man.request::<LuaScript>("scripts/test.lua").unwrap();
|
||||||
|
res_man.watch("scripts/test.lua", false).unwrap();
|
||||||
|
drop(res_man);
|
||||||
|
|
||||||
|
let script = Script::new("test.lua", script);
|
||||||
|
let scripts = ScriptList::new(vec![script]);
|
||||||
|
world.spawn((scripts,));
|
||||||
|
}
|
|
@ -9,3 +9,4 @@ edition = "2021"
|
||||||
anyhow = "1.0.81"
|
anyhow = "1.0.81"
|
||||||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||||
lyra-math = { path = "../lyra-math" }
|
lyra-math = { path = "../lyra-math" }
|
||||||
|
lyra-reflect = { path = "../lyra-reflect" }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod node;
|
mod node;
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
|
|
||||||
mod world_transform;
|
mod world_transform;
|
||||||
|
@ -12,6 +13,10 @@ pub(crate) mod lyra_engine {
|
||||||
pub(crate) mod ecs {
|
pub(crate) mod ecs {
|
||||||
pub use lyra_ecs::*;
|
pub use lyra_ecs::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) mod reflect {
|
||||||
|
pub use lyra_reflect::*;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A flag spawned on all scene node entities
|
/// A flag spawned on all scene node entities
|
||||||
|
@ -27,7 +32,9 @@ pub struct SceneNodeRoot;
|
||||||
/// This SceneGraph is special in the sense that it is literally just an ECS world with methods
|
/// This SceneGraph is special in the sense that it is literally just an ECS world with methods
|
||||||
/// implemented for it that make it easier to use for a SceneGraph.
|
/// implemented for it that make it easier to use for a SceneGraph.
|
||||||
//#[derive(Default)]
|
//#[derive(Default)]
|
||||||
|
#[derive(Clone, Reflect)]
|
||||||
pub struct SceneGraph {
|
pub struct SceneGraph {
|
||||||
|
#[reflect(skip)]
|
||||||
pub(crate) world: World,
|
pub(crate) world: World,
|
||||||
root_node: SceneNode,
|
root_node: SceneNode,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity};
|
use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity};
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::SceneGraph;
|
use crate::{SceneGraph, lyra_engine};
|
||||||
|
|
||||||
/// A node inside of the Scene
|
/// A node inside of the Scene
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq, Reflect)]
|
||||||
pub struct SceneNode {
|
pub struct SceneNode {
|
||||||
|
#[reflect(skip)]
|
||||||
parent: Option<Entity>,
|
parent: Option<Entity>,
|
||||||
|
#[reflect(skip)]
|
||||||
entity: Entity
|
entity: Entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,13 @@ lyra-game = { path = "../lyra-game" }
|
||||||
thiserror = "1.0.50"
|
thiserror = "1.0.50"
|
||||||
anyhow = "1.0.77"
|
anyhow = "1.0.77"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
|
atomic_refcell = "0.1.13"
|
||||||
|
|
||||||
# enabled with lua feature
|
# enabled with lua feature
|
||||||
#mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
|
#mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
|
||||||
elua = { path = "./elua", optional = true }
|
elua = { path = "./elua", optional = true }
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
|
paste = "1.0.14"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 54c9926a04cdef657289fd67730c0b85d1bdda3e
|
Subproject commit a761f4094bc18190285b4687ec804161fea874b6
|
|
@ -12,3 +12,4 @@ proc-macro = true
|
||||||
proc-macro2 = "1.0.70"
|
proc-macro2 = "1.0.70"
|
||||||
quote = "1.0.33"
|
quote = "1.0.33"
|
||||||
syn = "2.0.41"
|
syn = "2.0.41"
|
||||||
|
paste = "1.0.14"
|
|
@ -0,0 +1,149 @@
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn::{parse_macro_input, Ident, Token};
|
||||||
|
|
||||||
|
pub(crate) struct HandleWrapUsage {
|
||||||
|
pub type_path: syn::Path,
|
||||||
|
/// The extra derives of the type.
|
||||||
|
pub override_name: Option<Ident>,
|
||||||
|
|
||||||
|
pub extra_builds: Option<syn::Block>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::parse::Parse for HandleWrapUsage {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let type_path: syn::Path = input.parse()?;
|
||||||
|
let mut s = Self {
|
||||||
|
type_path,
|
||||||
|
override_name: None,
|
||||||
|
extra_builds: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
while input.peek(Token![,]) {
|
||||||
|
let _: Token![,] = input.parse()?;
|
||||||
|
|
||||||
|
if input.peek(syn::Ident) {
|
||||||
|
let ident: syn::Ident = input.parse()?;
|
||||||
|
let ident_str = ident.to_string();
|
||||||
|
let ident_str = ident_str.as_str();
|
||||||
|
|
||||||
|
match ident_str {
|
||||||
|
"name" => {
|
||||||
|
let _eq: Token![=] = input.parse()?;
|
||||||
|
|
||||||
|
let name: Ident = input.parse()?;
|
||||||
|
s.override_name = Some(name);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(syn::Error::new_spanned(ident, "unknown wrapper command"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}/* else if input.parse::<Block(syn::Block) {
|
||||||
|
let block = input.parse()?;
|
||||||
|
s.extra_builds = block;
|
||||||
|
} */
|
||||||
|
|
||||||
|
if let Ok(block) = input.parse::<syn::Block>() {
|
||||||
|
s.extra_builds = Some(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let input = parse_macro_input!(input as HandleWrapUsage);
|
||||||
|
|
||||||
|
let handle_name = &input.type_path.segments.last().unwrap().ident;
|
||||||
|
|
||||||
|
let base_name = input.override_name.unwrap_or_else(|| handle_name.clone());
|
||||||
|
let wrapper_name = format_ident!("Lua{}Handle", base_name);
|
||||||
|
//let wrapper_name = Ident::new(&format!("Lua{}", handle_name.to_string()), handle_name.span());
|
||||||
|
let ud_name = format!("{}Handle", base_name.to_string());
|
||||||
|
|
||||||
|
let extras = input.extra_builds;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[derive(Clone, Reflect)]
|
||||||
|
pub struct #wrapper_name(pub ResHandle<#handle_name>);
|
||||||
|
|
||||||
|
impl Deref for #wrapper_name {
|
||||||
|
type Target = ResHandle<#handle_name>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ResHandle<#handle_name>> for #wrapper_name {
|
||||||
|
fn from(value: ResHandle<#handle_name>) -> Self {
|
||||||
|
#wrapper_name(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elua::Userdata for #wrapper_name {
|
||||||
|
fn name() -> String {
|
||||||
|
#ud_name.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
||||||
|
builder.field_getter("path", |_, this| Ok(this.path()));
|
||||||
|
builder.field_getter("version", |_, this| Ok(this.version()));
|
||||||
|
builder.field_getter("uuid", |_, this| Ok(this.uuid().to_string()));
|
||||||
|
builder.field_getter("state", |_, this| {
|
||||||
|
let name = if this.is_loaded() {
|
||||||
|
"ready"
|
||||||
|
} else if this.get_error().is_some() {
|
||||||
|
"error"
|
||||||
|
} else { "loading" };
|
||||||
|
|
||||||
|
Ok(name)
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("is_watched", |_, this, ()| {
|
||||||
|
Ok(this.is_watched())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("is_loaded", |_, this, ()| {
|
||||||
|
Ok(this.is_loaded())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("is_loaded", |_, this, ()| {
|
||||||
|
Ok(this.is_loaded())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("wait_until_loaded", |_, this, ()| {
|
||||||
|
this.wait_recurse_dependencies_load();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
|
Ok(ScriptBorrow::from_component::<ResHandle<#handle_name>>(None))
|
||||||
|
});
|
||||||
|
builder.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
|
Ok(ScriptBorrow::from_component(Some(this.0.clone())))
|
||||||
|
});
|
||||||
|
|
||||||
|
#extras
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLua<'a> for #wrapper_name {
|
||||||
|
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
||||||
|
let tyname = val.type_name();
|
||||||
|
let ud = val.as_userdata()
|
||||||
|
.ok_or(elua::Error::type_mismatch(#ud_name, &tyname))?;
|
||||||
|
let ud = ud.as_ref::<#wrapper_name>()?;
|
||||||
|
|
||||||
|
Ok(ud.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaWrapper for #wrapper_name {
|
||||||
|
fn wrapped_type_id() -> std::any::TypeId {
|
||||||
|
TypeId::of::<ResHandle<#handle_name>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.into()
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
use handle_macro::lua_wrap_handle_impl;
|
||||||
|
use lua_macro::wrap_lua_struct_impl;
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, Path, Token, token, parenthesized, punctuated::Punctuated, braced};
|
use syn::{parse_macro_input, Path, Token, token, parenthesized, punctuated::Punctuated, braced};
|
||||||
|
@ -5,8 +7,14 @@ use syn::{parse_macro_input, Path, Token, token, parenthesized, punctuated::Punc
|
||||||
mod mat_wrapper;
|
mod mat_wrapper;
|
||||||
use mat_wrapper::MatWrapper;
|
use mat_wrapper::MatWrapper;
|
||||||
|
|
||||||
const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
mod lua_macro;
|
||||||
const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
|
||||||
|
mod handle_macro;
|
||||||
|
|
||||||
|
// pub use lua_macro::wrap_lua_struct;
|
||||||
|
|
||||||
|
pub(crate) const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||||
|
pub(crate) const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
||||||
|
|
||||||
pub(crate) struct MetaMethod {
|
pub(crate) struct MetaMethod {
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
|
@ -720,4 +728,14 @@ pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn wrap_lua_struct(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
wrap_lua_struct_impl(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn lua_wrap_handle(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
lua_wrap_handle_impl(input)
|
||||||
}
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
use proc_macro2::Span;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, Path, Ident};
|
||||||
|
|
||||||
|
use crate::{VecWrapper, WrapUsage, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE};
|
||||||
|
|
||||||
|
/// Creates a wrapper type for a VecN from the engine math library.
|
||||||
|
pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let input = parse_macro_input!(input as WrapUsage);
|
||||||
|
|
||||||
|
let path: Path = input.type_path;
|
||||||
|
let type_name = &path.segments.last()
|
||||||
|
.expect("Failure to find typename in macro usage!")
|
||||||
|
.ident;
|
||||||
|
let wrapper_typename = Ident::new(&format!("Lua{}", type_name), Span::call_site());
|
||||||
|
|
||||||
|
let vec_wrapper = {
|
||||||
|
let name_str = type_name.to_string();
|
||||||
|
if name_str.contains("Vec") {
|
||||||
|
Some(VecWrapper {})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO: fix this so it doesn't cause a stack overflow
|
||||||
|
/* let vec_wrapper_fields = vec_wrapper.as_ref().map(|vec|
|
||||||
|
vec.to_field_tokens(&path, &wrapper_typename)); */
|
||||||
|
let vec_wrapper_fields: Option<proc_macro2::TokenStream> = None;
|
||||||
|
let vec_wrapper_methods = vec_wrapper.as_ref().map(|vec|
|
||||||
|
vec.to_method_tokens(&path, &wrapper_typename));
|
||||||
|
|
||||||
|
let derive_idents_iter = input.derive_idents.iter();
|
||||||
|
let custom_methods = input.custom_methods;
|
||||||
|
let custom_fields = input.custom_fields;
|
||||||
|
|
||||||
|
let field_get_set_pairs = input.field_idents.iter().map(|i| {
|
||||||
|
let is = i.to_string();
|
||||||
|
quote! {
|
||||||
|
builder.field_getter(#is, |_, this| {
|
||||||
|
Ok(this.#i)
|
||||||
|
});
|
||||||
|
builder.field_setter(#is, |_, this, #i| {
|
||||||
|
this.#i = #i;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let new_fn_idents = {
|
||||||
|
let idents = if input.new_fn_idents.is_empty() {
|
||||||
|
input.field_idents.iter()
|
||||||
|
} else {
|
||||||
|
input.new_fn_idents.iter()
|
||||||
|
};
|
||||||
|
|
||||||
|
let idents_c = idents.clone();
|
||||||
|
|
||||||
|
if !input.skip_new_fn {
|
||||||
|
quote! {
|
||||||
|
builder.function("new", |_, ( #(#idents_c),* )| {
|
||||||
|
Ok(#wrapper_typename(#path::new( #(#idents),* )))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else { quote!() }
|
||||||
|
};
|
||||||
|
|
||||||
|
let matrix_wrapper_methods = input.matrix.as_ref().map(|m|
|
||||||
|
m.to_method_tokens(&path, &wrapper_typename));
|
||||||
|
let matrix_wrapper_fields = input.matrix.as_ref().map(|m|
|
||||||
|
m.to_field_tokens(&path, &wrapper_typename));
|
||||||
|
|
||||||
|
let meta_method_idents = {
|
||||||
|
let idents = input.meta_method_idents.iter().map(|metamethod| {
|
||||||
|
metamethod.to_tokens(&wrapper_typename)
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#(#idents)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc_macro::TokenStream::from(quote! {
|
||||||
|
#[derive(Clone, Copy, lyra_reflect::Reflect, #(#derive_idents_iter),*)]
|
||||||
|
pub struct #wrapper_typename(#[reflect(skip)] pub(crate) #path);
|
||||||
|
|
||||||
|
impl std::ops::Deref for #wrapper_typename {
|
||||||
|
type Target = #path;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for #wrapper_typename {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> elua::FromLua<'lua> for #wrapper_typename {
|
||||||
|
fn from_lua(_lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
|
match value {
|
||||||
|
elua::Value::Userdata(ud) => Ok(*ud.as_ref::<Self>()?),
|
||||||
|
_ => panic!("Attempt to get {} from a {} value", stringify!(#wrapper_typename), value.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elua::Userdata for #wrapper_typename {
|
||||||
|
fn name() -> String {
|
||||||
|
stringify!(#type_name).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
||||||
|
#(#field_get_set_pairs)*
|
||||||
|
|
||||||
|
#matrix_wrapper_fields
|
||||||
|
#vec_wrapper_fields
|
||||||
|
|
||||||
|
#custom_fields
|
||||||
|
|
||||||
|
#new_fn_idents
|
||||||
|
|
||||||
|
builder.method(#FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
|
Ok(crate::ScriptBorrow::from_component::<#path>(Some(this.0.clone())))
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
|
Ok(crate::ScriptBorrow::from_component::<#path>(None))
|
||||||
|
});
|
||||||
|
|
||||||
|
#meta_method_idents
|
||||||
|
|
||||||
|
#matrix_wrapper_methods
|
||||||
|
#vec_wrapper_methods
|
||||||
|
|
||||||
|
#custom_methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl lyra_scripting::lua::LuaWrapper for #wrapper_typename {
|
||||||
|
fn wrapped_type_id() -> std::any::TypeId {
|
||||||
|
let t = std::any::TypeId::of::<#path>();
|
||||||
|
println!("Got id of {}, it is {:?}", stringify!(#path), t);
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> elua::FromLuaVec<'a> for #wrapper_typename {
|
||||||
|
fn from_lua_value_vec(state: &'a elua::State, mut values: elua::ValueVec<'a>) -> elua::Result<Self> {
|
||||||
|
use elua::FromLua;
|
||||||
|
|
||||||
|
if let Some(val) = values.pop_front() {
|
||||||
|
#wrapper_typename::from_lua(state, val)
|
||||||
|
} else {
|
||||||
|
Err(elua::Error::IncorrectArgCount {
|
||||||
|
arg_expected: 1,
|
||||||
|
arg_count: values.len() as i32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, sync::{Arc, Mutex}};
|
||||||
|
|
||||||
use lyra_ecs::{ResourceObject, Entity, World};
|
use lyra_ecs::{ResourceObject, Entity, World};
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ pub struct ScriptData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides an API to a scripting context.
|
/// Provides an API to a scripting context.
|
||||||
pub trait ScriptApiProvider {
|
pub trait ScriptApiProvider: Send + Sync {
|
||||||
/// The type used as the script's context.
|
/// The type used as the script's context.
|
||||||
type ScriptContext;
|
type ScriptContext;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ pub trait ScriptApiProvider {
|
||||||
/// A storage for a [`ScriptHost`]'s api providers
|
/// A storage for a [`ScriptHost`]'s api providers
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ScriptApiProviders<T: ScriptHost> {
|
pub struct ScriptApiProviders<T: ScriptHost> {
|
||||||
pub apis: Vec<Box<dyn ScriptApiProvider<ScriptContext = T::ScriptContext>>>,
|
pub apis: Vec<Arc<Mutex<dyn ScriptApiProvider<ScriptContext = T::ScriptContext>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ScriptHost> ScriptApiProviders<T> {
|
impl<T: ScriptHost> ScriptApiProviders<T> {
|
||||||
|
@ -70,7 +70,7 @@ impl<T: ScriptHost> ScriptApiProviders<T> {
|
||||||
where
|
where
|
||||||
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static
|
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static
|
||||||
{
|
{
|
||||||
self.apis.push(Box::new(provider));
|
self.apis.push(Arc::new(Mutex::new(provider)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{ptr::NonNull, ops::{Range, Deref}};
|
use std::{ptr::NonNull, ops::Deref};
|
||||||
|
|
||||||
use lyra_ecs::{ComponentColumn, ComponentInfo, Archetype, ArchetypeId, ArchetypeEntityId, query::dynamic::{DynamicType, QueryDynamicType}, query::Fetch, Entity};
|
use lyra_ecs::{query::dynamic::DynamicViewStateIter, Entity};
|
||||||
use lyra_reflect::TypeRegistry;
|
use lyra_reflect::TypeRegistry;
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
|
@ -8,130 +8,6 @@ use super::ReflectLuaProxy;
|
||||||
|
|
||||||
use crate::ScriptWorldPtr;
|
use crate::ScriptWorldPtr;
|
||||||
|
|
||||||
/// A reimplementation of lyra_ecs::FetchDynamicType that doesn't store references and
|
|
||||||
/// uses a pointer instead.
|
|
||||||
/// This makes it easier to expose to Lua
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FetchDynamicType {
|
|
||||||
col: NonNull<ComponentColumn>,
|
|
||||||
info: ComponentInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Fetch<'a> for FetchDynamicType {
|
|
||||||
type Item = DynamicType;
|
|
||||||
|
|
||||||
fn dangling() -> Self {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_item(&mut self, entity: ArchetypeEntityId) -> Self::Item {
|
|
||||||
let ptr = unsafe { self.col.as_ref().borrow_ptr() };
|
|
||||||
let ptr = NonNull::new_unchecked(ptr.as_ptr()
|
|
||||||
.add(entity.0 as usize * self.info.layout().size()));
|
|
||||||
|
|
||||||
DynamicType {
|
|
||||||
info: self.info,
|
|
||||||
ptr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<lyra_ecs::query::dynamic::FetchDynamicType<'a>> for FetchDynamicType {
|
|
||||||
fn from(value: lyra_ecs::query::dynamic::FetchDynamicType<'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
col: NonNull::from(value.col),
|
|
||||||
info: value.info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DynamicViewRow {
|
|
||||||
entity: Entity,
|
|
||||||
item: Vec<DynamicType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DynamicViewIter {
|
|
||||||
world_ptr: ScriptWorldPtr,
|
|
||||||
queries: Vec<QueryDynamicType>,
|
|
||||||
fetchers: Vec<FetchDynamicType>,
|
|
||||||
archetypes: Vec<NonNull<Archetype>>,
|
|
||||||
next_archetype: usize,
|
|
||||||
component_indices: Range<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<lyra_ecs::query::dynamic::DynamicViewIter<'a>> for DynamicViewIter {
|
|
||||||
fn from(value: lyra_ecs::query::dynamic::DynamicViewIter<'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
world_ptr: ScriptWorldPtr::from_ref(value.world),
|
|
||||||
queries: value.queries,
|
|
||||||
fetchers: value.fetchers.into_iter().map(|f| FetchDynamicType::from(f)).collect(),
|
|
||||||
archetypes: value.archetypes.into_iter().map(|a| NonNull::from(a)).collect(),
|
|
||||||
next_archetype: value.next_archetype,
|
|
||||||
component_indices: value.component_indices,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for DynamicViewIter {
|
|
||||||
type Item = DynamicViewRow;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
|
||||||
if let Some(entity_index) = self.component_indices.next() {
|
|
||||||
let mut fetch_res = vec![];
|
|
||||||
|
|
||||||
let entity_index = ArchetypeEntityId(entity_index);
|
|
||||||
for fetcher in self.fetchers.iter_mut() {
|
|
||||||
if !fetcher.can_visit_item(entity_index) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
let i = unsafe { fetcher.get_item(entity_index) };
|
|
||||||
fetch_res.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if fetch_res.len() != self.fetchers.len() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let arch = unsafe { self.archetypes.get_unchecked(self.next_archetype - 1).as_ref() };
|
|
||||||
let entity = arch.entity_at_index(entity_index).unwrap();
|
|
||||||
let row = DynamicViewRow {
|
|
||||||
entity,
|
|
||||||
item: fetch_res,
|
|
||||||
};
|
|
||||||
|
|
||||||
return Some(row);
|
|
||||||
} else {
|
|
||||||
if self.next_archetype >= self.archetypes.len() {
|
|
||||||
return None; // ran out of archetypes to go through
|
|
||||||
}
|
|
||||||
|
|
||||||
let arch_id = self.next_archetype;
|
|
||||||
self.next_archetype += 1;
|
|
||||||
let arch = unsafe { self.archetypes.get_unchecked(arch_id).as_ref() };
|
|
||||||
|
|
||||||
if arch.entity_indexes().len() == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.queries.iter().any(|q| !q.can_visit_archetype(arch)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let world = self.world_ptr.as_ref();
|
|
||||||
|
|
||||||
self.fetchers = self.queries.iter()
|
|
||||||
.map(|q| unsafe { q.fetch(world, ArchetypeId(arch_id as u64), arch) } )
|
|
||||||
.map(|f| FetchDynamicType::from(f))
|
|
||||||
.collect();
|
|
||||||
self.component_indices = 0..arch.entity_indexes().len() as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
pub struct ReflectedItem<'a> {
|
pub struct ReflectedItem<'a> {
|
||||||
//pub proxy: &'a ReflectLuaProxy,
|
//pub proxy: &'a ReflectLuaProxy,
|
||||||
|
@ -147,7 +23,7 @@ pub struct ReflectedRow<'a> {
|
||||||
|
|
||||||
pub struct ReflectedIterator {
|
pub struct ReflectedIterator {
|
||||||
pub world: ScriptWorldPtr,
|
pub world: ScriptWorldPtr,
|
||||||
pub dyn_view: DynamicViewIter,
|
pub dyn_view: DynamicViewStateIter,
|
||||||
pub reflected_components: Option<NonNull<TypeRegistry>>
|
pub reflected_components: Option<NonNull<TypeRegistry>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +31,9 @@ impl ReflectedIterator {
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
pub fn next_lua<'a>(&mut self, lua: &'a elua::State) -> Option<ReflectedRow<'a>> {
|
pub fn next_lua<'a>(&mut self, lua: &'a elua::State) -> Option<ReflectedRow<'a>> {
|
||||||
use elua::AsLua;
|
use elua::AsLua;
|
||||||
|
|
||||||
let n = self.dyn_view.next();
|
let world = self.world.as_ref();
|
||||||
|
let n = self.dyn_view.next(world);
|
||||||
|
|
||||||
if let Some(row) = n {
|
if let Some(row) = n {
|
||||||
if self.reflected_components.is_none() {
|
if self.reflected_components.is_none() {
|
||||||
|
@ -166,7 +43,7 @@ impl ReflectedIterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dynamic_row = vec![];
|
let mut dynamic_row = vec![];
|
||||||
for d in row.item.iter() {
|
for d in row.row.iter() {
|
||||||
let id = d.info.type_id().as_rust();
|
let id = d.info.type_id().as_rust();
|
||||||
let reflected_components =
|
let reflected_components =
|
||||||
unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
|
unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use lyra_resource::{ResourceLoader, ResHandle};
|
use lyra_resource::{loader::{PinedBoxLoaderFuture, ResourceLoader}, ResHandle, ResourceData};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LuaScript {
|
pub struct LuaScript {
|
||||||
|
@ -8,6 +8,20 @@ pub struct LuaScript {
|
||||||
pub(crate) bytes: Vec<u8>,
|
pub(crate) bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ResourceData for LuaScript {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dependencies(&self) -> Vec<lyra_resource::UntypedResHandle> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct LuaLoader;
|
pub struct LuaLoader;
|
||||||
|
|
||||||
|
@ -20,24 +34,33 @@ impl ResourceLoader for LuaLoader {
|
||||||
&["text/lua"]
|
&["text/lua"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, _resource_manager: &mut lyra_resource::ResourceManager, path: &str) -> Result<std::sync::Arc<dyn lyra_resource::ResourceStorage>, lyra_resource::LoaderError> {
|
fn load(&self, _resource_manager: lyra_resource::ResourceManager, path: &str) -> PinedBoxLoaderFuture {
|
||||||
let bytes = std::fs::read(path)?;
|
let path = path.to_string();
|
||||||
|
Box::pin(async move {
|
||||||
|
let bytes = std::fs::read(&path)?;
|
||||||
|
|
||||||
let s = ResHandle::new_ready(path, LuaScript {
|
let s = LuaScript {
|
||||||
bytes
|
bytes
|
||||||
});
|
};
|
||||||
|
|
||||||
Ok(Arc::new(s))
|
Ok(Box::new(s) as Box<dyn ResourceData>)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_bytes(&self, _resource_manager: &mut lyra_resource::ResourceManager, bytes: Vec<u8>, offset: usize, length: usize) -> Result<std::sync::Arc<dyn lyra_resource::ResourceStorage>, lyra_resource::LoaderError> {
|
fn load_bytes(&self, _resource_manager: lyra_resource::ResourceManager, bytes: Vec<u8>, offset: usize, length: usize) -> PinedBoxLoaderFuture {
|
||||||
let end = offset + length;
|
Box::pin(async move {
|
||||||
let bytes = bytes[offset..end].to_vec();
|
let end = offset + length;
|
||||||
|
let bytes = bytes[offset..end].to_vec();
|
||||||
let s = ResHandle::new_ready("from bytes", LuaScript {
|
|
||||||
bytes
|
let s = LuaScript {
|
||||||
});
|
bytes
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Arc::new(s))
|
Ok(Box::new(s) as Box<dyn ResourceData>)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_erased_handle(&self) -> Arc<dyn lyra_resource::ResourceStorage> {
|
||||||
|
Arc::from(ResHandle::<LuaScript>::new_loading(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
use lyra_ecs::ResourceObject;
|
use std::any::TypeId;
|
||||||
use lyra_reflect::Reflect;
|
|
||||||
|
|
||||||
use crate::{lua::{wrappers::{LuaActionHandler, LuaDeltaTime, LuaModelComponent}, LuaContext, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
use lyra_ecs::ResourceObject;
|
||||||
|
use lyra_reflect::{Reflect, TypeRegistry};
|
||||||
|
use lyra_resource::gltf::Gltf;
|
||||||
|
|
||||||
|
use crate::{lua::{wrappers::{LuaGltfHandle, LuaActionHandler, LuaDeltaTime, LuaResHandleToComponent, LuaSceneHandle}, LuaContext, ReflectLuaProxy, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LyraEcsApiProvider;
|
pub struct LyraEcsApiProvider;
|
||||||
|
@ -11,8 +14,26 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
|
|
||||||
fn prepare_world(&mut self, world: &mut lyra_ecs::World) {
|
fn prepare_world(&mut self, world: &mut lyra_ecs::World) {
|
||||||
world.register_lua_convert::<LuaDeltaTime>();
|
world.register_lua_convert::<LuaDeltaTime>();
|
||||||
world.register_lua_wrapper::<LuaModelComponent>();
|
world.register_lua_wrapper::<LuaSceneHandle>();
|
||||||
world.register_lua_wrapper::<LuaActionHandler>();
|
world.register_lua_wrapper::<LuaActionHandler>();
|
||||||
|
|
||||||
|
let mut registry = world.get_resource_mut::<TypeRegistry>();
|
||||||
|
|
||||||
|
let reg_type = registry.get_type_or_default(TypeId::of::<Gltf>());
|
||||||
|
reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<LuaGltfHandle>());
|
||||||
|
|
||||||
|
let l = LuaResHandleToComponent::new(
|
||||||
|
|lua, res| {
|
||||||
|
if let Some(gltf) = res.as_typed::<Gltf>() {
|
||||||
|
Some(lua.create_userdata(LuaGltfHandle(gltf)).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
reg_type.add_data(l);
|
||||||
|
|
||||||
|
//reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<LuaGltfHandle>());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||||
|
@ -21,7 +42,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
let globals = ctx.globals()?;
|
let globals = ctx.globals()?;
|
||||||
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
||||||
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
||||||
globals.set("ModelComponent", ctx.create_proxy::<LuaModelComponent>()?)?;
|
globals.set("SceneComponent", ctx.create_proxy::<LuaSceneHandle>()?)?;
|
||||||
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
||||||
|
|
||||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||||
|
|
|
@ -30,6 +30,7 @@ impl ScriptHost for LuaHost {
|
||||||
});
|
});
|
||||||
|
|
||||||
for provider in providers.apis.iter_mut() {
|
for provider in providers.apis.iter_mut() {
|
||||||
|
let mut provider = provider.lock().unwrap();
|
||||||
provider.expose_api(script_data, &mut ctx)?;
|
provider.expose_api(script_data, &mut ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ impl ScriptHost for LuaHost {
|
||||||
|
|
||||||
fn setup_script(&mut self, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>) -> Result<(), ScriptError> {
|
fn setup_script(&mut self, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>) -> Result<(), ScriptError> {
|
||||||
for provider in providers.apis.iter_mut() {
|
for provider in providers.apis.iter_mut() {
|
||||||
|
let mut provider = provider.lock().unwrap();
|
||||||
provider.setup_script(script_data, ctx)?;
|
provider.setup_script(script_data, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +59,7 @@ impl ScriptHost for LuaHost {
|
||||||
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
||||||
function_name: &str) -> Result<(), ScriptError> {
|
function_name: &str) -> Result<(), ScriptError> {
|
||||||
for provider in providers.apis.iter_mut() {
|
for provider in providers.apis.iter_mut() {
|
||||||
|
let mut provider = provider.lock().unwrap();
|
||||||
provider.update_script_environment(world.clone(), script_data, ctx)?;
|
provider.update_script_environment(world.clone(), script_data, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub fn lua_scripts_create_contexts(
|
||||||
let script_name = script.name();
|
let script_name = script.name();
|
||||||
let _span = debug_span!("lua", script = script_name).entered();
|
let _span = debug_span!("lua", script = script_name).entered();
|
||||||
|
|
||||||
if let Some(script_res) = &script.res_handle().try_data_ref() {
|
if let Some(script_res) = &script.res_handle().data_ref() {
|
||||||
debug!("Loading script...");
|
debug!("Loading script...");
|
||||||
let mut script_ctx =
|
let mut script_ctx =
|
||||||
host.load_script(&script_res.bytes, &script_data, &mut providers)?;
|
host.load_script(&script_res.bytes, &script_data, &mut providers)?;
|
||||||
|
@ -74,14 +74,14 @@ pub fn lua_scripts_create_contexts(
|
||||||
/// Note: This only works if the script is watched. See [`lyra_resource::ResourceManager::watch`].
|
/// Note: This only works if the script is watched. See [`lyra_resource::ResourceManager::watch`].
|
||||||
pub fn lua_scripts_reload_system(
|
pub fn lua_scripts_reload_system(
|
||||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||||
mut resman: ResMut<ResourceManager>,
|
resman: ResMut<ResourceManager>,
|
||||||
view: View<&ScriptList<LuaScript>>,
|
view: View<&ScriptList<LuaScript>>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
for scripts in view.into_iter() {
|
for scripts in view.into_iter() {
|
||||||
for script in scripts.iter() {
|
for script in scripts.iter() {
|
||||||
let handle = script.res_handle();
|
let handle = script.res_handle();
|
||||||
if handle.is_watched() {
|
if handle.is_watched() {
|
||||||
let handle_path = handle.path();
|
let handle_path = handle.path().unwrap();
|
||||||
let watch_recv = resman.watcher_event_recv(&handle_path).unwrap();
|
let watch_recv = resman.watcher_event_recv(&handle_path).unwrap();
|
||||||
|
|
||||||
match watch_recv.try_recv() {
|
match watch_recv.try_recv() {
|
||||||
|
@ -199,7 +199,7 @@ impl Plugin for LuaScriptingPlugin {
|
||||||
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
||||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||||
|
|
||||||
let mut loader = world
|
let loader = world
|
||||||
.try_get_resource_mut::<ResourceManager>()
|
.try_get_resource_mut::<ResourceManager>()
|
||||||
.expect("Add 'ResourceManager' to the world before trying to add this plugin");
|
.expect("Add 'ResourceManager' to the world before trying to add this plugin");
|
||||||
loader.register_loader::<LuaLoader>();
|
loader.register_loader::<LuaLoader>();
|
||||||
|
|
|
@ -2,12 +2,12 @@ use std::{ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
||||||
use elua::AsLua;
|
use elua::AsLua;
|
||||||
use lyra_ecs::{query::dynamic::QueryDynamicType, CommandQueue, Commands, DynamicBundle, World};
|
use lyra_ecs::{query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}, CommandQueue, Commands, DynamicBundle, World};
|
||||||
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
||||||
use lyra_resource::ResourceManager;
|
use lyra_resource::ResourceManager;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
reflect_user_data, wrappers::LuaResHandle, DynamicViewIter, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
|
reflect_user_data, wrappers::LuaResHandleToComponent, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
||||||
|
@ -114,7 +114,8 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
}
|
}
|
||||||
|
|
||||||
let world = unsafe { this.inner.as_ref() };
|
let world = unsafe { this.inner.as_ref() };
|
||||||
let mut view = world.dynamic_view();
|
//let mut view = world.dynamic_view();
|
||||||
|
let mut view = DynamicViewState::new();
|
||||||
|
|
||||||
for (idx, comp) in queries.into_iter().enumerate() {
|
for (idx, comp) in queries.into_iter().enumerate() {
|
||||||
match comp {
|
match comp {
|
||||||
|
@ -160,7 +161,7 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
let iter = view.into_iter();
|
let iter = view.into_iter();
|
||||||
let mut reflected_iter = ReflectedIterator {
|
let mut reflected_iter = ReflectedIterator {
|
||||||
world: this.clone(),
|
world: this.clone(),
|
||||||
dyn_view: DynamicViewIter::from(iter),
|
dyn_view: DynamicViewStateIter::from(iter),
|
||||||
reflected_components: None,
|
reflected_components: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -297,12 +298,19 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.method_mut("request_res", |_, this, path: String| {
|
.method_mut("request_res", |lua, this, path: String| {
|
||||||
let world = this.as_mut();
|
let world: &mut World = this.as_mut();
|
||||||
let mut man = world.get_resource_mut::<ResourceManager>();
|
let man = world.get_resource_mut::<ResourceManager>();
|
||||||
let handle = man.request_raw(&path).unwrap();
|
let handle = man.request_raw(&path).unwrap();
|
||||||
|
|
||||||
Ok(LuaResHandle::from(handle))
|
// get the actual resource handle wrapper
|
||||||
|
let registry = world.get_resource::<TypeRegistry>();
|
||||||
|
let ty = registry.get_type(handle.resource_type_id())
|
||||||
|
.expect("Could not find asset type in registry");
|
||||||
|
let data = ty.get_data::<LuaResHandleToComponent>()
|
||||||
|
.expect("Asset type does not have 'LuaResHandleToComponent' as TypeData");
|
||||||
|
|
||||||
|
Ok((data.fn_to_lua)(lua, handle).unwrap())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
use std::{any::TypeId, ops::Deref};
|
||||||
|
use elua::{AnyUserdata, AsLua, FromLua, State, Value};
|
||||||
|
use lyra_resource::{gltf::Gltf, ResHandle, UntypedResHandle};
|
||||||
|
use lyra_game::scene::SceneGraph;
|
||||||
|
use lyra_reflect::{Reflect, TypeData};
|
||||||
|
use lyra_scripting_derive::lua_wrap_handle;
|
||||||
|
|
||||||
|
use crate::{lua::{LuaWrapper, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow};
|
||||||
|
|
||||||
|
pub struct LuaResHandleToComponent {
|
||||||
|
/// Create the userdata component that
|
||||||
|
pub fn_to_lua: fn(&State, UntypedResHandle) -> Option<AnyUserdata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaResHandleToComponent {
|
||||||
|
pub fn new(f: fn(&State, UntypedResHandle) -> Option<AnyUserdata>) -> Self {
|
||||||
|
Self {
|
||||||
|
fn_to_lua: f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeData for LuaResHandleToComponent {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn boxed_clone(&self) -> Box<dyn TypeData> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaResHandle(pub UntypedResHandle);
|
||||||
|
|
||||||
|
impl Deref for LuaResHandle {
|
||||||
|
type Target = UntypedResHandle;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UntypedResHandle> for LuaResHandle {
|
||||||
|
fn from(value: UntypedResHandle) -> Self {
|
||||||
|
LuaResHandle(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elua::Userdata for LuaResHandle {
|
||||||
|
fn name() -> String {
|
||||||
|
"Handle".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
||||||
|
builder.field_getter("path", |_, this| Ok(this.path()));
|
||||||
|
builder.field_getter("version", |_, this| Ok(this.version()));
|
||||||
|
builder.field_getter("uuid", |_, this| Ok(this.uuid().to_string()));
|
||||||
|
builder.field_getter("state", |_, this| {
|
||||||
|
let name = if this.is_loaded() {
|
||||||
|
"ready"
|
||||||
|
} else if this.get_error().is_some() {
|
||||||
|
"error"
|
||||||
|
} else { "loading" };
|
||||||
|
|
||||||
|
Ok(name)
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("is_watched", |_, this, ()| {
|
||||||
|
Ok(this.is_watched())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("is_loaded", |_, this, ()| {
|
||||||
|
Ok(this.is_loaded())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method("wait_until_loaded", |_, this, ()| {
|
||||||
|
this.wait_recurse_dependencies_load();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| {
|
||||||
|
let handle = &this.0;
|
||||||
|
|
||||||
|
if let Some(handle) = handle.as_typed::<SceneGraph>() {
|
||||||
|
LuaSceneHandle(handle).as_lua(lua)
|
||||||
|
} else if let Some(handle) = handle.as_typed::<Gltf>() {
|
||||||
|
LuaGltfHandle(handle).as_lua(lua)
|
||||||
|
} else {
|
||||||
|
Ok(elua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLua<'a> for LuaResHandle {
|
||||||
|
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
||||||
|
let tyname = val.type_name();
|
||||||
|
let ud = val.as_userdata()
|
||||||
|
.ok_or(elua::Error::type_mismatch("Handle", &tyname))?;
|
||||||
|
let handle = ud.as_ref::<LuaResHandle>()?;
|
||||||
|
|
||||||
|
Ok(handle.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_wrap_handle!(SceneGraph, name=Scene, {});
|
||||||
|
lua_wrap_handle!(Gltf, {
|
||||||
|
builder.method("scenes", |lua, this, ()| {
|
||||||
|
if let Some(data) = this.0.data_ref() {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
for (i, scene) in data.scenes.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_seti(i, LuaSceneHandle(scene.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Table(table))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,11 +4,8 @@ pub use math::*;
|
||||||
pub mod delta_time;
|
pub mod delta_time;
|
||||||
pub use delta_time::*;
|
pub use delta_time::*;
|
||||||
|
|
||||||
pub mod res_handle;
|
|
||||||
pub use res_handle::*;
|
|
||||||
|
|
||||||
pub mod model_comp;
|
|
||||||
pub use model_comp::*;
|
|
||||||
|
|
||||||
pub mod input_actions;
|
pub mod input_actions;
|
||||||
pub use input_actions::*;
|
pub use input_actions::*;
|
||||||
|
|
||||||
|
pub mod asset;
|
||||||
|
pub use asset::*;
|
|
@ -1,77 +0,0 @@
|
||||||
use std::{ops::Deref, sync::Arc};
|
|
||||||
|
|
||||||
use elua::{AsLua, FromLua};
|
|
||||||
use lyra_game::scene::ModelComponent;
|
|
||||||
use lyra_resource::{Model, ResHandle, ResourceStorage};
|
|
||||||
|
|
||||||
use crate::lua::FN_NAME_INTERNAL_AS_COMPONENT;
|
|
||||||
|
|
||||||
use super::LuaModelComponent;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LuaResHandle(pub Arc<dyn ResourceStorage>);
|
|
||||||
|
|
||||||
impl Deref for LuaResHandle {
|
|
||||||
type Target = dyn ResourceStorage;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.0.deref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Arc<dyn ResourceStorage>> for LuaResHandle {
|
|
||||||
fn from(value: Arc<dyn ResourceStorage>) -> Self {
|
|
||||||
LuaResHandle(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl elua::Userdata for LuaResHandle {
|
|
||||||
fn name() -> String {
|
|
||||||
"Handle".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
|
||||||
builder.field_getter("path", |_, this| Ok(this.path()));
|
|
||||||
builder.field_getter("version", |_, this| Ok(this.version()));
|
|
||||||
builder.field_getter("uuid", |_, this| Ok(this.uuid().to_string()));
|
|
||||||
builder.field_getter("state", |_, this| {
|
|
||||||
let name = match this.state() {
|
|
||||||
lyra_resource::ResourceState::Loading => "loading",
|
|
||||||
lyra_resource::ResourceState::Ready => "ready",
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(name)
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.method("is_watched", |_, this, ()| {
|
|
||||||
Ok(this.is_watched())
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.method("is_loaded", |_, this, ()| {
|
|
||||||
Ok(this.is_loaded())
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| {
|
|
||||||
let any = this.0.as_any();
|
|
||||||
match any.downcast_ref::<ResHandle<Model>>() {
|
|
||||||
Some(model) => {
|
|
||||||
LuaModelComponent(ModelComponent(model.clone())).as_lua(lua)
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
Ok(elua::Value::Nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromLua<'a> for LuaResHandle {
|
|
||||||
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
|
||||||
let tyname = val.type_name();
|
|
||||||
let ud = val.as_userdata()
|
|
||||||
.ok_or(elua::Error::type_mismatch("Handle", &tyname))?;
|
|
||||||
let handle = ud.as_ref::<LuaResHandle>()?;
|
|
||||||
|
|
||||||
Ok(handle.clone())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +1,20 @@
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
use lyra_ecs::Component;
|
use lyra_ecs::Component;
|
||||||
use lyra_resource::ResHandle;
|
use lyra_resource::{ResHandle, ResourceData};
|
||||||
|
|
||||||
use crate::lyra_engine;
|
use crate::lyra_engine;
|
||||||
|
|
||||||
static SCRIPT_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
|
static SCRIPT_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Script<T> {
|
pub struct Script<T: ResourceData> {
|
||||||
res: ResHandle<T>,
|
res: ResHandle<T>,
|
||||||
name: String,
|
name: String,
|
||||||
id: u64
|
id: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Script<T> {
|
impl<T: ResourceData> Script<T> {
|
||||||
pub fn new(name: &str, script: ResHandle<T>) -> Self {
|
pub fn new(name: &str, script: ResHandle<T>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res: script,
|
res: script,
|
||||||
|
@ -38,15 +38,15 @@ impl<T> Script<T> {
|
||||||
|
|
||||||
/// A list of scripts
|
/// A list of scripts
|
||||||
#[derive(Clone, Default, Component)]
|
#[derive(Clone, Default, Component)]
|
||||||
pub struct ScriptList<T: 'static>(Vec<Script<T>>);
|
pub struct ScriptList<T: ResourceData>(Vec<Script<T>>);
|
||||||
|
|
||||||
impl<T> ScriptList<T> {
|
impl<T: ResourceData> ScriptList<T> {
|
||||||
pub fn new(list: Vec<Script<T>>) -> Self {
|
pub fn new(list: Vec<Script<T>>) -> Self {
|
||||||
Self(list)
|
Self(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::Deref for ScriptList<T> {
|
impl<T: ResourceData> std::ops::Deref for ScriptList<T> {
|
||||||
type Target = Vec<Script<T>>;
|
type Target = Vec<Script<T>>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -54,7 +54,7 @@ impl<T> std::ops::Deref for ScriptList<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::DerefMut for ScriptList<T> {
|
impl<T: ResourceData> std::ops::DerefMut for ScriptList<T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue