diff --git a/examples/testbed/scripts/test.lua b/examples/testbed/scripts/test.lua index 75e8dd5..1e67ad3 100644 --- a/examples/testbed/scripts/test.lua +++ b/examples/testbed/scripts/test.lua @@ -1,10 +1,12 @@ ---local cube: resource = world:request_res("loader", "assets/cube-texture-embedded.gltf") - ---cube = nil - function on_init() local cube = world:request_res("assets/cube-texture-embedded.gltf") print("Loaded textured cube") + + local pos = Transform.from_translation(Vec3.new(0, 0, -8.0)) + local cube_comp = ModelComponent.new(cube) + + local e = world:spawn(pos, cube_comp) + print("spawned entity " .. tostring(e)) end --[[ function on_first() diff --git a/lyra-game/src/plugin.rs b/lyra-game/src/plugin.rs index e014e61..f1b8db7 100644 --- a/lyra-game/src/plugin.rs +++ b/lyra-game/src/plugin.rs @@ -1,4 +1,4 @@ -use lyra_ecs::Commands; +use lyra_ecs::CommandQueue; use lyra_resource::ResourceManager; use crate::EventsPlugin; @@ -109,10 +109,22 @@ pub struct DefaultPlugins; impl Plugin for DefaultPlugins { fn setup(&self, game: &mut Game) { + CommandQueuePlugin.setup(game); EventsPlugin.setup(game); InputPlugin.setup(game); ResourceManagerPlugin.setup(game); WindowPlugin::default().setup(game); DeltaTimePlugin.setup(game); } +} + +/// A plugin that creates a CommandQueue, and inserts it into the world as a Resource. +/// The queue is processed at the end of every system execution in the GraphExecutor. +#[derive(Default)] +pub struct CommandQueuePlugin; + +impl Plugin for CommandQueuePlugin { + fn setup(&self, game: &mut Game) { + game.world_mut().add_resource(CommandQueue::default()); + } } \ No newline at end of file diff --git a/lyra-scripting/src/lua/script.rs b/lyra-scripting/src/lua/script.rs index e344a59..cbf7258 100644 --- a/lyra-scripting/src/lua/script.rs +++ b/lyra-scripting/src/lua/script.rs @@ -47,9 +47,6 @@ impl ScriptHost for LuaHost { provider.setup_script(script_data, ctx)?; } - let ctx = ctx.lock().expect("Failure to get Lua ScriptContext"); - try_call_lua_function(&ctx, "on_init")?; - Ok(()) } diff --git a/lyra-scripting/src/lua/system.rs b/lyra-scripting/src/lua/system.rs index ea4fbfa..7b0effc 100644 --- a/lyra-scripting/src/lua/system.rs +++ b/lyra-scripting/src/lua/system.rs @@ -1,7 +1,5 @@ -use std::ptr::NonNull; - use anyhow::anyhow; -use lyra_ecs::{query::{Entities, ResMut, View}, CommandQueue, Commands, World}; +use lyra_ecs::{query::{Entities, ResMut, View}, World}; use lyra_game::{game::GameStages, plugin::Plugin}; use lyra_reflect::TypeRegistry; use lyra_resource::ResourceManager; @@ -12,15 +10,13 @@ use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, Scrip use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript}; /// A system that creates the script contexts in the world as new scripts are found -pub fn lua_scripts_create_contexts<'a>( +pub fn lua_scripts_create_contexts( world: &mut World, mut host: ResMut, mut contexts: ResMut>, mut providers: ResMut>, view: View<(Entities, &ScriptList)>, ) -> anyhow::Result<()> { - world.add_resource_default::(); - for (en, scripts) in view.into_iter() { for script in scripts.iter() { if !contexts.has_context(script.id()) { @@ -43,6 +39,24 @@ pub fn lua_scripts_create_contexts<'a>( host.setup_script(&script_data, &mut script_ctx, &mut providers)?; trace!("Finished setting up script"); + // call on_init, handle the error + let world_ptr = ScriptWorldPtr::from_ref(&world); + match host.call_script( + world_ptr, + &script_data, + &mut script_ctx, + &mut providers, + "on_init", + ) { + Ok(()) => {} + Err(e) => match e { + ScriptError::MluaError(m) => { + error!("Script '{}' ran into an error: {}", script.name(), m); + } + ScriptError::Other(_) => return Err(e.into()), + }, + } + contexts.add_context(script.id(), script_ctx); break; } else { @@ -52,14 +66,6 @@ pub fn lua_scripts_create_contexts<'a>( } } - let mut ptr = NonNull::from(world); - let world = unsafe { ptr.as_ref() }; - let mut queue = world.get_resource_mut::(); - - let mut commands = Commands::new(&mut queue, unsafe { ptr.as_mut() }); - commands.execute(unsafe { ptr.as_mut() }).unwrap(); - //commands.execute(unsafe { world_ptr.as_mut() } )?; - Ok(()) } diff --git a/lyra-scripting/src/lua/world.rs b/lyra-scripting/src/lua/world.rs index 20e8c52..615812d 100644 --- a/lyra-scripting/src/lua/world.rs +++ b/lyra-scripting/src/lua/world.rs @@ -1,8 +1,8 @@ use std::{ptr::NonNull, sync::Arc}; -use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptEntity, ScriptWorldPtr}; +use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr}; use elua::AsLua; -use lyra_ecs::{query::dynamic::QueryDynamicType, Commands, DynamicBundle}; +use lyra_ecs::{query::dynamic::QueryDynamicType, CommandQueue, Commands, DynamicBundle, World}; use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry}; use lyra_resource::ResourceManager; @@ -64,10 +64,38 @@ impl elua::Userdata for ScriptWorldPtr { builder: &mut elua::UserdataBuilder<'a, Self>, ) -> elua::Result<()> { builder - .method_mut("spawn", |_, this, bundle: ScriptDynamicBundle| { + .method_mut("spawn", |_, this, vals: elua::ValueVec| { let world = this.as_mut(); - Ok(ScriptEntity(world.spawn(bundle.0))) + let mut bundle = DynamicBundle::new(); + + //while let Some(val) = vals.pop_front() { + for (i, val) in vals.into_iter().enumerate() { + let ud = val.as_userdata().ok_or( + elua::Error::bad_arg( + Some("World:spawn"), + 2 + i as i32, // i starts at 0 + Some("components..."), + Arc::new(elua::Error::runtime("provided component is not userdata")), + ))?; + + let script_brw = ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?; + let reflect = script_brw.reflect_branch.as_component_unchecked(); + + let refl_data = script_brw.data.unwrap(); + //let refl_data = refl_data.as_ref(); + reflect.bundle_insert(&mut bundle, refl_data); + } + + // defer the entity spawn + // safety: Commands borrows Entities from World, the resource borrows from the world resouces, + // they are borrowing different parts of World. + let world_ptr: *mut World = world; + let mut commands_queue = world.get_resource_mut::(); + let mut commands = Commands::new(&mut commands_queue, unsafe { &mut *world_ptr }); + let entity = commands.spawn(bundle); + + Ok(ScriptEntity(entity)) }) .method_mut( "view",