Compare commits
2 Commits
1f43a9d4da
...
90b821f95c
Author | SHA1 | Date |
---|---|---|
SeanOMik | 90b821f95c | |
SeanOMik | 5dfc073db5 |
|
@ -72,7 +72,7 @@
|
||||||
"--no-run",
|
"--no-run",
|
||||||
"--lib",
|
"--lib",
|
||||||
"--package=lyra-ecs",
|
"--package=lyra-ecs",
|
||||||
"world::tests::view_change_tracking",
|
"command::tests::deferred_commands",
|
||||||
"--",
|
"--",
|
||||||
"--exact --nocapture"
|
"--exact --nocapture"
|
||||||
],
|
],
|
||||||
|
|
|
@ -1456,7 +1456,6 @@ dependencies = [
|
||||||
"paste",
|
"paste",
|
||||||
"rand",
|
"rand",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"unique",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1520,7 +1519,6 @@ dependencies = [
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-math",
|
"lyra-math",
|
||||||
"lyra-reflect-derive",
|
"lyra-reflect-derive",
|
||||||
"lyra-resource",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2688,12 +2686,6 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unique"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d360722e1f3884f5b14d332185f02ff111f771f0c76a313268fe6af1409aba96"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urlencoding"
|
name = "urlencoding"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
--[[ function on_init()
|
--local cube: resource = world:request_res("loader", "assets/cube-texture-embedded.gltf")
|
||||||
print("Lua script was initialized!")
|
|
||||||
|
--cube = nil
|
||||||
|
|
||||||
|
function on_init()
|
||||||
|
local cube = world:request_res("assets/cube-texture-embedded.gltf")
|
||||||
|
print("Loaded textured cube")
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_first()
|
--[[ function on_first()
|
||||||
print("Lua's first function was called")
|
print("Lua's first function was called")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -14,11 +19,6 @@ function on_update()
|
||||||
---@type number
|
---@type number
|
||||||
local dt = world:resource(DeltaTime)
|
local dt = world:resource(DeltaTime)
|
||||||
|
|
||||||
local v = Vec3.new(10, 10, 10)
|
|
||||||
v:move_by(50, 50, 50)
|
|
||||||
v:move_by(Vec3.new(50, 50, 50))
|
|
||||||
print("v = " .. tostring(v))
|
|
||||||
|
|
||||||
world:view(function (t)
|
world:view(function (t)
|
||||||
t:translate(0, 0.5 * dt, 0)
|
t:translate(0, 0.5 * dt, 0)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ lyra-ecs-derive = { path = "./lyra-ecs-derive" }
|
||||||
lyra-math = { path = "../lyra-math", optional = true }
|
lyra-math = { path = "../lyra-math", optional = true }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
thiserror = "1.0.50"
|
thiserror = "1.0.50"
|
||||||
unique = "0.9.1"
|
|
||||||
paste = "1.0.14"
|
paste = "1.0.14"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
use std::{cell::RefMut, collections::VecDeque, mem, ptr::{self, NonNull}};
|
use std::{any::Any, cell::RefMut, collections::VecDeque, ptr::{self, NonNull}};
|
||||||
|
|
||||||
use unique::Unique;
|
|
||||||
|
|
||||||
use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, World};
|
use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, World};
|
||||||
|
|
||||||
pub trait Command {
|
pub trait Command: Any {
|
||||||
|
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any>;
|
||||||
|
|
||||||
fn run(self, world: &mut World) -> anyhow::Result<()>;
|
fn run(self, world: &mut World) -> anyhow::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Command for F
|
impl<F> Command for F
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut World) -> anyhow::Result<()>
|
F: FnOnce(&mut World) -> anyhow::Result<()> + 'static
|
||||||
{
|
{
|
||||||
|
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, world: &mut World) -> anyhow::Result<()> {
|
fn run(self, world: &mut World) -> anyhow::Result<()> {
|
||||||
self(world)
|
self(world)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunCommand = unsafe fn(cmd: Unique<()>, world: &mut World) -> anyhow::Result<()>;
|
type RunCommand = unsafe fn(cmd: Box<dyn Command>, world: &mut World) -> anyhow::Result<()>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CommandQueue(VecDeque<(RunCommand, Unique<()>)>);
|
pub struct CommandQueue(VecDeque<(RunCommand, Box<dyn Command>)>);
|
||||||
|
|
||||||
pub struct Commands<'a, 'b> {
|
pub struct Commands<'a, 'b> {
|
||||||
queue: &'b mut CommandQueue,
|
queue: &'b mut CommandQueue,
|
||||||
|
@ -36,31 +40,26 @@ impl<'a, 'b> Commands<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a command to the end of the command queue
|
/// Add a command to the end of the command queue
|
||||||
pub fn add<C: Command>(&mut self, mut cmd: C) {
|
pub fn add<C: Command>(&mut self, cmd: C) {
|
||||||
// get an owned pointer to the command, then forget it to ensure its destructor isn't ran
|
let cmd = Box::new(cmd);
|
||||||
let ptr = Unique::from(&mut cmd).cast::<()>();
|
|
||||||
mem::forget(cmd);
|
|
||||||
|
|
||||||
let run_fn = |cmd_ptr: Unique<()>, world: &mut World| unsafe {
|
let run_fn = |cmd: Box<dyn Command>, world: &mut World| {
|
||||||
let cmd = cmd_ptr.cast::<C>();
|
let cmd = cmd.as_any_boxed()
|
||||||
let cmd = ptr::read(cmd.as_ptr());
|
.downcast::<C>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
cmd.run(world)?;
|
cmd.run(world)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.queue.0.push_back((run_fn, ptr));
|
self.queue.0.push_back((run_fn, cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn<B: Bundle>(&mut self, mut bundle: B) -> Entity {
|
pub fn spawn<B: Bundle + 'static>(&mut self, bundle: B) -> Entity {
|
||||||
let e = self.entities.reserve();
|
let e = self.entities.reserve();
|
||||||
|
|
||||||
let bundle_ptr = Unique::from(&mut bundle);
|
|
||||||
mem::forget(bundle);
|
|
||||||
//let bundle_box = Box::new(bundle);
|
|
||||||
|
|
||||||
self.add(move |world: &mut World| {
|
self.add(move |world: &mut World| {
|
||||||
let bundle = unsafe { ptr::read(bundle_ptr.as_ptr()) };
|
|
||||||
world.spawn_into(e, bundle);
|
world.spawn_into(e, bundle);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
@ -101,7 +100,7 @@ impl FnArgFetcher for Commands<'_, '_> {
|
||||||
let world = unsafe { world_ptr.as_mut() };
|
let world = unsafe { world_ptr.as_mut() };
|
||||||
|
|
||||||
let mut cmds = Commands::new(&mut state, world);
|
let mut cmds = Commands::new(&mut state, world);
|
||||||
// safety: Commands has a mut borrow to entities in the world
|
// safety: Commands has a mut borrow only to entities in the world
|
||||||
let world = unsafe { world_ptr.as_mut() };
|
let world = unsafe { world_ptr.as_mut() };
|
||||||
cmds.execute(world).unwrap()
|
cmds.execute(world).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -111,4 +110,41 @@ pub fn execute_deferred_commands(world: &mut World, mut commands: RefMut<Command
|
||||||
commands.execute(world)?;
|
commands.execute(world)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
use crate::{system::{GraphExecutor, IntoSystem}, tests::Vec2, Commands, DynTypeId, World};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deferred_commands() {
|
||||||
|
let mut world = World::new();
|
||||||
|
let vecs = vec![Vec2::rand(), Vec2::rand(), Vec2::rand()];
|
||||||
|
world.spawn((vecs[0],));
|
||||||
|
world.spawn((vecs[1],));
|
||||||
|
world.spawn((vecs[2],));
|
||||||
|
|
||||||
|
let spawned_vec = Vec2::rand();
|
||||||
|
|
||||||
|
let spawned_vec_cl = spawned_vec.clone();
|
||||||
|
let test_sys = move |mut commands: Commands| -> anyhow::Result<()> {
|
||||||
|
commands.spawn((spawned_vec_cl.clone(),));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut graph_exec = GraphExecutor::new();
|
||||||
|
graph_exec.insert_system("test", test_sys.into_system(), &[]);
|
||||||
|
graph_exec.execute(NonNull::from(&world), true).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(world.entities.len(), 4);
|
||||||
|
|
||||||
|
// there's only one archetype
|
||||||
|
let arch = world.archetypes.values().next().unwrap();
|
||||||
|
let col = arch.get_column(DynTypeId::of::<Vec2>()).unwrap();
|
||||||
|
let vec2: &Vec2 = unsafe { col.get(3) };
|
||||||
|
assert_eq!(vec2.clone(), spawned_vec);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -35,7 +35,6 @@ impl Entities {
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("id is {}", self.next_id.0);
|
|
||||||
let new_id = self.next_id;
|
let new_id = self.next_id;
|
||||||
self.next_id.0 += 1;
|
self.next_id.0 += 1;
|
||||||
|
|
||||||
|
@ -47,6 +46,11 @@ impl Entities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of spawned entities
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.next_id.0 as usize - self.dead.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves the Archetype Record for the entity
|
/// Retrieves the Archetype Record for the entity
|
||||||
pub(crate) fn entity_record(&self, entity: Entity) -> Option<Record> {
|
pub(crate) fn entity_record(&self, entity: Entity) -> Option<Record> {
|
||||||
self.arch_index.get(&entity.id).cloned()
|
self.arch_index.get(&entity.id).cloned()
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::{ptr::NonNull, marker::PhantomData};
|
use std::{any::Any, marker::PhantomData, ptr::NonNull};
|
||||||
|
|
||||||
use unique::Unique;
|
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
use crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery, ResMut, Res}};
|
use crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery, ResMut, Res}};
|
||||||
|
|
||||||
|
@ -12,7 +11,6 @@ pub trait FnArgFetcher {
|
||||||
|
|
||||||
type Arg<'a, 'state>: FnArgFetcher<State = Self::State>;
|
type Arg<'a, 'state>: FnArgFetcher<State = Self::State>;
|
||||||
|
|
||||||
//fn new() -> Self;
|
|
||||||
fn create_state(world: NonNull<World>) -> Self::State;
|
fn create_state(world: NonNull<World>) -> Self::State;
|
||||||
|
|
||||||
/// Return the appropriate world access if this fetcher gets the world directly.
|
/// Return the appropriate world access if this fetcher gets the world directly.
|
||||||
|
@ -40,7 +38,7 @@ pub struct FnSystem<F, Args> {
|
||||||
inner: F,
|
inner: F,
|
||||||
//#[allow(dead_code)]
|
//#[allow(dead_code)]
|
||||||
//args: Args,
|
//args: Args,
|
||||||
arg_state: Option<Vec<Unique<()>>>,
|
arg_state: Option<Vec<Box<dyn Any>>>,
|
||||||
_marker: PhantomData<Args>,
|
_marker: PhantomData<Args>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +58,8 @@ macro_rules! impl_fn_system_tuple {
|
||||||
paste! {
|
paste! {
|
||||||
$(
|
$(
|
||||||
// get the arg fetcher, create its state, and get the arg
|
// get the arg fetcher, create its state, and get the arg
|
||||||
|
|
||||||
let mut [<state_ $name:lower>]: $name::State = $name::create_state(world);
|
let mut [<state_ $name:lower>]: $name::State = $name::create_state(world);
|
||||||
let [<$name:lower>] = $name::get(&mut [<state_ $name:lower>], world);
|
let [<$name:lower>] = $name::get(&mut [<state_ $name:lower>], world);
|
||||||
|
|
||||||
)+
|
)+
|
||||||
|
|
||||||
(self.inner)($( [<$name:lower>] ),+)?;
|
(self.inner)($( [<$name:lower>] ),+)?;
|
||||||
|
@ -71,9 +67,8 @@ macro_rules! impl_fn_system_tuple {
|
||||||
let mut state = Vec::new();
|
let mut state = Vec::new();
|
||||||
$(
|
$(
|
||||||
// type erase the now modified state, and store it
|
// type erase the now modified state, and store it
|
||||||
let [<state_ $name:lower _ptr>] = Unique::from(&mut [<state_ $name:lower>]);
|
let boxed = Box::new([<state_ $name:lower>]) as Box<dyn Any>;
|
||||||
std::mem::forget([<state_ $name:lower>]);
|
state.push(boxed);
|
||||||
state.push([<state_ $name:lower _ptr>].cast::<()>());
|
|
||||||
)+
|
)+
|
||||||
|
|
||||||
self.arg_state = Some(state);
|
self.arg_state = Some(state);
|
||||||
|
@ -84,41 +79,22 @@ macro_rules! impl_fn_system_tuple {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_deferred(&mut self, world: NonNull<World>) -> anyhow::Result<()> {
|
fn execute_deferred(&mut self, world: NonNull<World>) -> anyhow::Result<()> {
|
||||||
|
let state = self.arg_state.as_mut().expect("Somehow there was no state");
|
||||||
|
|
||||||
$(
|
$(
|
||||||
let s = self.arg_state.as_mut().expect("Somehow there was no state").pop().unwrap();
|
let arg_state_box = state.pop()
|
||||||
let s = unsafe { std::ptr::read(s.cast::<$name::State>().as_ptr()) };
|
.expect("Missing expected arg state");
|
||||||
$name::apply_deferred(s, world);
|
let arg_state = *arg_state_box.downcast::<$name::State>()
|
||||||
|
.unwrap();
|
||||||
|
$name::apply_deferred(arg_state, world);
|
||||||
)+
|
)+
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* impl<F, $($name: FnArg,)+> IntoSystem<($($name,)+)> for F
|
|
||||||
where
|
|
||||||
/* for <'a> &'a mut F:
|
|
||||||
FnMut($($name,)+) -> anyhow::Result<()>,
|
|
||||||
FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a, '_>,)+) -> anyhow::Result<()>, */
|
|
||||||
F: FnMut($($name,)+) -> anyhow::Result<()>,
|
|
||||||
F: for<'a> FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a, '_>,)+) -> anyhow::Result<()>,
|
|
||||||
{
|
|
||||||
type System = FnSystem<F, ($($name::Fetcher,)+)>;
|
|
||||||
|
|
||||||
fn into_system(self) -> Self::System {
|
|
||||||
FnSystem {
|
|
||||||
//args: ($($name::Fetcher::new(),)+),
|
|
||||||
inner: self,
|
|
||||||
arg_state: None,
|
|
||||||
_marker: PhantomData::<($($name::Fetcher,)+)>::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
impl<F, $($name: FnArgFetcher,)+> IntoSystem<($($name,)+)> for F
|
impl<F, $($name: FnArgFetcher,)+> IntoSystem<($($name,)+)> for F
|
||||||
where
|
where
|
||||||
/* for <'a> &'a mut F:
|
|
||||||
FnMut($($name,)+) -> anyhow::Result<()>,
|
|
||||||
FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a, '_>,)+) -> anyhow::Result<()>, */
|
|
||||||
F: FnMut($($name,)+) -> anyhow::Result<()>,
|
F: FnMut($($name,)+) -> anyhow::Result<()>,
|
||||||
F: for<'a> FnMut($($name::Arg<'a, '_>,)+) -> anyhow::Result<()>,
|
F: for<'a> FnMut($($name::Arg<'a, '_>,)+) -> anyhow::Result<()>,
|
||||||
{
|
{
|
||||||
|
@ -126,7 +102,6 @@ macro_rules! impl_fn_system_tuple {
|
||||||
|
|
||||||
fn into_system(self) -> Self::System {
|
fn into_system(self) -> Self::System {
|
||||||
FnSystem {
|
FnSystem {
|
||||||
//args: ($($name::Fetcher::new(),)+),
|
|
||||||
inner: self,
|
inner: self,
|
||||||
arg_state: None,
|
arg_state: None,
|
||||||
_marker: PhantomData::<($($name,)+)>::default(),
|
_marker: PhantomData::<($($name,)+)>::default(),
|
||||||
|
|
|
@ -93,7 +93,6 @@ impl World {
|
||||||
let entity_arch_id = archetype.add_entity(entity, bundle, &tick);
|
let entity_arch_id = archetype.add_entity(entity, bundle, &tick);
|
||||||
|
|
||||||
// store archetype
|
// store archetype
|
||||||
println!("About to store arch, cap is {}, len is {}", self.archetypes.capacity(), self.archetypes.len());
|
|
||||||
self.archetypes.insert(new_arch_id, archetype);
|
self.archetypes.insert(new_arch_id, archetype);
|
||||||
|
|
||||||
// Create entity record and store it
|
// Create entity record and store it
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 22b6d218bdb6a5aafc0efd4fb80a67d2c796d0e7
|
Subproject commit 70e2985cc44fdb30cdf2157c50d2f0e3385e08fa
|
|
@ -89,10 +89,10 @@ pub trait ScriptHost: Default + ResourceObject {
|
||||||
fn setup_script(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext,
|
fn setup_script(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext,
|
||||||
providers: &mut ScriptApiProviders<Self>) -> Result<(), ScriptError>;
|
providers: &mut ScriptApiProviders<Self>) -> Result<(), ScriptError>;
|
||||||
|
|
||||||
/// Executes the update step for the script.
|
/// Calls a event function in the script.
|
||||||
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
||||||
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
||||||
function_name: &str) -> Result<(), ScriptError>;
|
event_fn_name: &str) -> Result<(), ScriptError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -76,8 +76,8 @@ impl ReflectBranch {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScriptBorrow {
|
pub struct ScriptBorrow {
|
||||||
reflect_branch: ReflectBranch,
|
pub(crate) reflect_branch: ReflectBranch,
|
||||||
data: Option<Box<dyn Reflect>>,
|
pub(crate) data: Option<Box<dyn Reflect>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ScriptBorrow {
|
impl Clone for ScriptBorrow {
|
||||||
|
@ -95,7 +95,7 @@ impl ScriptBorrow {
|
||||||
/// Creates a ScriptBorrow from a Component
|
/// Creates a ScriptBorrow from a Component
|
||||||
pub fn from_component<T>(data: Option<T>) -> Self
|
pub fn from_component<T>(data: Option<T>) -> Self
|
||||||
where
|
where
|
||||||
T: Reflect + Component + Default + 'static
|
T: Reflect + Component + 'static
|
||||||
{
|
{
|
||||||
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
|
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ impl ScriptBorrow {
|
||||||
/// Creates a ScriptBorrow from a Resource.
|
/// Creates a ScriptBorrow from a Resource.
|
||||||
pub fn from_resource<T>(data: Option<T>) -> Self
|
pub fn from_resource<T>(data: Option<T>) -> Self
|
||||||
where
|
where
|
||||||
T: Reflect + ResourceObject + Default + 'static
|
T: Reflect + ResourceObject + 'static
|
||||||
{
|
{
|
||||||
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
|
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use lyra_ecs::ResourceObject;
|
use lyra_ecs::ResourceObject;
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{lua::{wrappers::LuaDeltaTime, LuaContext, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
use crate::{lua::{wrappers::{LuaDeltaTime, LuaModelComponent}, LuaContext, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LyraEcsApiProvider;
|
pub struct LyraEcsApiProvider;
|
||||||
|
@ -11,6 +11,7 @@ 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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
|
@ -19,6 +20,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>()?)?;
|
||||||
|
|
||||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||||
globals.set("DeltaTime", dt_table)?;
|
globals.set("DeltaTime", dt_table)?;
|
||||||
|
|
|
@ -171,7 +171,6 @@ impl elua::Userdata for ScriptDynamicBundle {
|
||||||
let reflect = script_brw.reflect_branch.as_component_unchecked();
|
let reflect = script_brw.reflect_branch.as_component_unchecked();
|
||||||
|
|
||||||
let refl_data = script_brw.data.unwrap();
|
let refl_data = script_brw.data.unwrap();
|
||||||
let refl_data = refl_data.as_ref();
|
|
||||||
reflect.bundle_insert(&mut this.0, refl_data);
|
reflect.bundle_insert(&mut this.0, refl_data);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl ScriptHost for LuaHost {
|
||||||
|
|
||||||
/// Runs the update step of the lua script.
|
/// Runs the update step of the lua script.
|
||||||
///
|
///
|
||||||
/// It looks for an `update` function with zero parameters in [`the ScriptContext`] and executes it.
|
/// It looks for an `update` function with zero parameters in the [`ScriptContext`] and executes it.
|
||||||
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
||||||
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> {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use lyra_ecs::{query::{Entities, ResMut, View}, World};
|
use lyra_ecs::{query::{Entities, ResMut, View}, CommandQueue, Commands, World};
|
||||||
use lyra_game::{game::GameStages, plugin::Plugin};
|
use lyra_game::{game::GameStages, plugin::Plugin};
|
||||||
use lyra_reflect::TypeRegistry;
|
use lyra_reflect::TypeRegistry;
|
||||||
use lyra_resource::ResourceManager;
|
use lyra_resource::ResourceManager;
|
||||||
|
@ -10,12 +12,15 @@ use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, Scrip
|
||||||
use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript};
|
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
|
/// A system that creates the script contexts in the world as new scripts are found
|
||||||
pub fn lua_scripts_create_contexts(
|
pub fn lua_scripts_create_contexts<'a>(
|
||||||
|
world: &mut World,
|
||||||
mut host: ResMut<LuaHost>,
|
mut host: ResMut<LuaHost>,
|
||||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||||
mut providers: ResMut<ScriptApiProviders<LuaHost>>,
|
mut providers: ResMut<ScriptApiProviders<LuaHost>>,
|
||||||
view: View<(Entities, &ScriptList<LuaScript>)>,
|
view: View<(Entities, &ScriptList<LuaScript>)>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
world.add_resource_default::<CommandQueue>();
|
||||||
|
|
||||||
for (en, scripts) in view.into_iter() {
|
for (en, scripts) in view.into_iter() {
|
||||||
for script in scripts.iter() {
|
for script in scripts.iter() {
|
||||||
if !contexts.has_context(script.id()) {
|
if !contexts.has_context(script.id()) {
|
||||||
|
@ -39,6 +44,7 @@ pub fn lua_scripts_create_contexts(
|
||||||
trace!("Finished setting up script");
|
trace!("Finished setting up script");
|
||||||
|
|
||||||
contexts.add_context(script.id(), script_ctx);
|
contexts.add_context(script.id(), script_ctx);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
trace!("Script is not loaded yet, skipping for now");
|
trace!("Script is not loaded yet, skipping for now");
|
||||||
}
|
}
|
||||||
|
@ -46,6 +52,14 @@ pub fn lua_scripts_create_contexts(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut ptr = NonNull::from(world);
|
||||||
|
let world = unsafe { ptr.as_ref() };
|
||||||
|
let mut queue = world.get_resource_mut::<CommandQueue>();
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use std::{ptr::NonNull, sync::Arc};
|
use std::{ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
|
use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptEntity, ScriptWorldPtr};
|
||||||
use elua::AsLua;
|
use elua::AsLua;
|
||||||
use lyra_ecs::query::dynamic::QueryDynamicType;
|
use lyra_ecs::{query::dynamic::QueryDynamicType, Commands, DynamicBundle};
|
||||||
use lyra_reflect::{TypeRegistry, ReflectWorldExt, RegisteredType};
|
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
||||||
use crate::{ScriptWorldPtr, ScriptEntity, ScriptDynamicBundle, ScriptBorrow};
|
use lyra_resource::ResourceManager;
|
||||||
|
|
||||||
use super::{reflect_user_data, DynamicViewIter, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_REFLECT_TYPE};
|
use super::{
|
||||||
|
reflect_user_data, wrappers::LuaResHandle, DynamicViewIter, LuaTableProxyLookup,
|
||||||
|
ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
||||||
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
|
@ -22,7 +26,10 @@ impl elua::Userdata for ScriptEntity {
|
||||||
"Entity".to_string()
|
"Entity".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<'a>(_: &elua::State, builder: &mut elua::userdata::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
fn build<'a>(
|
||||||
|
_: &elua::State,
|
||||||
|
builder: &mut elua::userdata::UserdataBuilder<'a, Self>,
|
||||||
|
) -> elua::Result<()> {
|
||||||
builder.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
|
builder.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
|
||||||
Ok(format!("{:?}", this.0))
|
Ok(format!("{:?}", this.0))
|
||||||
});
|
});
|
||||||
|
@ -52,134 +59,159 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
"World".to_string()
|
"World".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<'a>(_: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
fn build<'a>(
|
||||||
|
_: &elua::State,
|
||||||
|
builder: &mut elua::UserdataBuilder<'a, Self>,
|
||||||
|
) -> elua::Result<()> {
|
||||||
builder
|
builder
|
||||||
.method_mut("spawn", |_, this, bundle: ScriptDynamicBundle| {
|
.method_mut("spawn", |_, this, bundle: ScriptDynamicBundle| {
|
||||||
let world = this.as_mut();
|
let world = this.as_mut();
|
||||||
|
|
||||||
Ok(ScriptEntity(world.spawn(bundle.0)))
|
Ok(ScriptEntity(world.spawn(bundle.0)))
|
||||||
})
|
})
|
||||||
.method_mut("view", |lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
|
.method_mut(
|
||||||
if queries.is_empty() {
|
"view",
|
||||||
return Err(
|
|lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
|
||||||
elua::Error::BadArgument { func: Some("World:view".to_string()), arg_index: 2, arg_name: Some("query...".to_string()),
|
if queries.is_empty() {
|
||||||
error: Arc::new(elua::Error::other(WorldError::LuaInvalidUsage("no component types provided".to_string())))
|
return Err(elua::Error::BadArgument {
|
||||||
});
|
func: Some("World:view".to_string()),
|
||||||
}
|
arg_index: 2,
|
||||||
|
arg_name: Some("query...".to_string()),
|
||||||
let world = unsafe { this.inner.as_ref() };
|
error: Arc::new(elua::Error::other(WorldError::LuaInvalidUsage(
|
||||||
let mut view = world.dynamic_view();
|
"no component types provided".to_string(),
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (idx, comp) in queries.into_iter().enumerate() {
|
let world = unsafe { this.inner.as_ref() };
|
||||||
match comp {
|
let mut view = world.dynamic_view();
|
||||||
elua::Value::Table(t) => {
|
|
||||||
let name: String = t.get(elua::MetaMethod::Name)?;
|
|
||||||
|
|
||||||
let lookup = world.try_get_resource::<LuaTableProxyLookup>()
|
for (idx, comp) in queries.into_iter().enumerate() {
|
||||||
.ok_or(elua::Error::runtime("Unable to lookup table proxy, none were ever registered!"))?;
|
match comp {
|
||||||
let info = lookup.comp_info_from_name.get(&name)
|
elua::Value::Table(t) => {
|
||||||
.ok_or_else(||
|
let name: String = t.get(elua::MetaMethod::Name)?;
|
||||||
elua::Error::BadArgument {
|
|
||||||
|
let lookup = world
|
||||||
|
.try_get_resource::<LuaTableProxyLookup>()
|
||||||
|
.ok_or(elua::Error::runtime(
|
||||||
|
"Unable to lookup table proxy, none were ever registered!",
|
||||||
|
))?;
|
||||||
|
let info = lookup.comp_info_from_name.get(&name).ok_or_else(
|
||||||
|
|| elua::Error::BadArgument {
|
||||||
func: Some("World:view".to_string()),
|
func: Some("World:view".to_string()),
|
||||||
arg_index: 2 + idx as i32,
|
arg_index: 2 + idx as i32,
|
||||||
arg_name: Some("query...".to_string()),
|
arg_name: Some("query...".to_string()),
|
||||||
error: Arc::new(
|
error: Arc::new(elua::Error::Runtime(format!(
|
||||||
elua::Error::Runtime(format!("the 'Table' with name {} is unknown to the engine!", name))
|
"the 'Table' with name {} is unknown to the engine!",
|
||||||
)
|
name
|
||||||
}
|
))),
|
||||||
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let dyn_type = QueryDynamicType::from_info(info.clone());
|
|
||||||
view.push(dyn_type);
|
|
||||||
},
|
|
||||||
elua::Value::Userdata(ud) => {
|
|
||||||
let reflect = ud.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
|
||||||
.expect("Type does not implement 'reflect_type' properly");
|
|
||||||
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
|
||||||
|
|
||||||
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
let dyn_type = QueryDynamicType::from_info(info.clone());
|
||||||
view.push(dyn_type);
|
view.push(dyn_type);
|
||||||
},
|
}
|
||||||
_ => todo!()
|
elua::Value::Userdata(ud) => {
|
||||||
}
|
let reflect = ud
|
||||||
}
|
.execute_function::<_, ScriptBorrow>(
|
||||||
|
FN_NAME_INTERNAL_REFLECT_TYPE,
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
|
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
||||||
|
|
||||||
let iter = view.into_iter();
|
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
||||||
let mut reflected_iter = ReflectedIterator {
|
view.push(dyn_type);
|
||||||
world: this.clone(),
|
}
|
||||||
dyn_view: DynamicViewIter::from(iter),
|
_ => todo!(),
|
||||||
reflected_components: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut current = world.current_tick();
|
|
||||||
let mut has_ticked = false;
|
|
||||||
|
|
||||||
while let Some(row) = reflected_iter.next_lua(lua) {
|
|
||||||
let r = row.row.into_iter()
|
|
||||||
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let (values, ptrs) = itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<()>>), _>(r);
|
|
||||||
let mult_val = elua::ValueVec::from(values);
|
|
||||||
let res: elua::ValueVec = system.exec(mult_val)?;
|
|
||||||
|
|
||||||
// if values were returned, find the type in the type registry, and apply the new values
|
|
||||||
if res.len() <= ptrs.len() {
|
|
||||||
// we only want to tick one time per system
|
|
||||||
if !has_ticked {
|
|
||||||
current = world.tick();
|
|
||||||
has_ticked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (comp, ptr) in res.into_iter().zip(ptrs) {
|
|
||||||
let lua_typeid = match &comp {
|
|
||||||
elua::Value::Userdata(ud) => {
|
|
||||||
let lua_comp = reflect_user_data(ud);
|
|
||||||
let refl_comp = lua_comp.reflect_branch.as_component_unchecked();
|
|
||||||
refl_comp.info.type_id.as_rust()
|
|
||||||
},
|
|
||||||
elua::Value::Table(tbl) => {
|
|
||||||
let name: String = tbl.get(elua::MetaMethod::Name)?;
|
|
||||||
|
|
||||||
let lookup = world.get_resource::<LuaTableProxyLookup>();
|
|
||||||
*lookup.typeid_from_name.get(&name).unwrap()
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
panic!("A userdata or table value was not returned!"); // TODO: Handle properly
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// update the component tick
|
|
||||||
let world = unsafe { this.inner.as_mut() };
|
|
||||||
let arch = world.entity_archetype_mut(row.entity).unwrap();
|
|
||||||
let idx = arch.entities().get(&row.entity).unwrap().clone();
|
|
||||||
let c = arch.get_column_mut(lua_typeid.into()).unwrap();
|
|
||||||
c.entity_ticks[idx.0 as usize] = current;
|
|
||||||
|
|
||||||
// apply the new component data
|
|
||||||
let reg = this.as_ref().get_resource::<TypeRegistry>();
|
|
||||||
let reg_type = reg.get_type(lua_typeid).unwrap();
|
|
||||||
|
|
||||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
|
||||||
// this should actually be safe since the ReflectedIterator
|
|
||||||
// attempts to get the type data before it is tried here
|
|
||||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
|
||||||
(proxy.fn_apply)(lua, ptr, &comp)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let msg = format!("Too many arguments were returned from the World view!
|
|
||||||
At most, the expected number of results is {}.", ptrs.len());
|
|
||||||
return Err(elua::Error::Runtime(msg));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
let iter = view.into_iter();
|
||||||
})
|
let mut reflected_iter = ReflectedIterator {
|
||||||
|
world: this.clone(),
|
||||||
|
dyn_view: DynamicViewIter::from(iter),
|
||||||
|
reflected_components: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut current = world.current_tick();
|
||||||
|
let mut has_ticked = false;
|
||||||
|
|
||||||
|
while let Some(row) = reflected_iter.next_lua(lua) {
|
||||||
|
let r = row
|
||||||
|
.row
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let (values, ptrs) =
|
||||||
|
itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<()>>), _>(r);
|
||||||
|
let mult_val = elua::ValueVec::from(values);
|
||||||
|
let res: elua::ValueVec = system.exec(mult_val)?;
|
||||||
|
|
||||||
|
// if values were returned, find the type in the type registry, and apply the new values
|
||||||
|
if res.len() <= ptrs.len() {
|
||||||
|
// we only want to tick one time per system
|
||||||
|
if !has_ticked {
|
||||||
|
current = world.tick();
|
||||||
|
has_ticked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (comp, ptr) in res.into_iter().zip(ptrs) {
|
||||||
|
let lua_typeid = match &comp {
|
||||||
|
elua::Value::Userdata(ud) => {
|
||||||
|
let lua_comp = reflect_user_data(ud);
|
||||||
|
let refl_comp =
|
||||||
|
lua_comp.reflect_branch.as_component_unchecked();
|
||||||
|
refl_comp.info.type_id.as_rust()
|
||||||
|
}
|
||||||
|
elua::Value::Table(tbl) => {
|
||||||
|
let name: String = tbl.get(elua::MetaMethod::Name)?;
|
||||||
|
|
||||||
|
let lookup = world.get_resource::<LuaTableProxyLookup>();
|
||||||
|
*lookup.typeid_from_name.get(&name).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("A userdata or table value was not returned!");
|
||||||
|
// TODO: Handle properly
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// update the component tick
|
||||||
|
let world = unsafe { this.inner.as_mut() };
|
||||||
|
let arch = world.entity_archetype_mut(row.entity).unwrap();
|
||||||
|
let idx = arch.entities().get(&row.entity).unwrap().clone();
|
||||||
|
let c = arch.get_column_mut(lua_typeid.into()).unwrap();
|
||||||
|
c.entity_ticks[idx.0 as usize] = current;
|
||||||
|
|
||||||
|
// apply the new component data
|
||||||
|
let reg = this.as_ref().get_resource::<TypeRegistry>();
|
||||||
|
let reg_type = reg.get_type(lua_typeid).unwrap();
|
||||||
|
|
||||||
|
let proxy = reg_type
|
||||||
|
.get_data::<ReflectLuaProxy>()
|
||||||
|
// this should actually be safe since the ReflectedIterator
|
||||||
|
// attempts to get the type data before it is tried here
|
||||||
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
|
(proxy.fn_apply)(lua, ptr, &comp)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let msg = format!(
|
||||||
|
"Too many arguments were returned from the World view!
|
||||||
|
At most, the expected number of results is {}.",
|
||||||
|
ptrs.len()
|
||||||
|
);
|
||||||
|
return Err(elua::Error::Runtime(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
.method_mut("resource", |lua, this, (ty,): (elua::Value,)| {
|
.method_mut("resource", |lua, this, (ty,): (elua::Value,)| {
|
||||||
let reflect = match ty {
|
let reflect = match ty {
|
||||||
elua::Value::Userdata(ud) => {
|
elua::Value::Userdata(ud) => ud
|
||||||
ud.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||||
.expect("Type does not implement 'reflect_type' properly")
|
.expect("Type does not implement 'reflect_type' properly"),
|
||||||
}
|
|
||||||
elua::Value::Table(t) => {
|
elua::Value::Table(t) => {
|
||||||
let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?;
|
let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?;
|
||||||
f.exec::<_, ScriptBorrow>(())
|
f.exec::<_, ScriptBorrow>(())
|
||||||
|
@ -190,24 +222,33 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/* let reflect = ty
|
/* let reflect = ty
|
||||||
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||||
.expect("Type does not implement 'reflect_type' properly"); */
|
.expect("Type does not implement 'reflect_type' properly"); */
|
||||||
|
|
||||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||||
if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
|
if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
|
||||||
let reg_type = this.as_ref().get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
let reg_type = this
|
||||||
|
.as_ref()
|
||||||
|
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
let proxy = reg_type
|
||||||
|
.get_data::<ReflectLuaProxy>()
|
||||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
|
|
||||||
(proxy.fn_as_lua)(lua, res_ptr.cast())
|
(proxy.fn_as_lua)(lua, res_ptr.cast()).and_then(|ud| ud.as_lua(lua))
|
||||||
.and_then(|ud| ud.as_lua(lua))
|
|
||||||
} else {
|
} else {
|
||||||
// if the resource is not found in the world, return nil
|
// if the resource is not found in the world, return nil
|
||||||
Ok(elua::Value::Nil)
|
Ok(elua::Value::Nil)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.method_mut("request_res", |_, this, path: String| {
|
||||||
|
let world = this.as_mut();
|
||||||
|
let mut man = world.get_resource_mut::<ResourceManager>();
|
||||||
|
let handle = man.request_raw(&path).unwrap();
|
||||||
|
|
||||||
|
Ok(LuaResHandle::from(handle))
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,10 @@ pub mod math;
|
||||||
pub use math::*;
|
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::*;
|
|
@ -0,0 +1,70 @@
|
||||||
|
use std::any::TypeId;
|
||||||
|
use std::{cell::Ref, sync::Arc};
|
||||||
|
|
||||||
|
use elua::{AsLua, FromLua};
|
||||||
|
use lyra_game::scene::ModelComponent;
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
|
use lyra_resource::{Model, ResHandle};
|
||||||
|
|
||||||
|
use crate::lua::LuaWrapper;
|
||||||
|
use crate::lyra_engine;
|
||||||
|
use crate::{lua::{FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptBorrow};
|
||||||
|
|
||||||
|
use super::LuaResHandle;
|
||||||
|
|
||||||
|
#[derive(Clone, Reflect)]
|
||||||
|
pub struct LuaModelComponent(ModelComponent);
|
||||||
|
|
||||||
|
impl elua::Userdata for LuaModelComponent {
|
||||||
|
fn name() -> String {
|
||||||
|
"ModelComponent".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build<'a>(_: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||||
|
builder
|
||||||
|
.function("new", |_, model: Ref<LuaResHandle>| {
|
||||||
|
let res = model.0.clone();
|
||||||
|
let res_any = res.as_arc_any();
|
||||||
|
match res_any.downcast::<ResHandle<Model>>() {
|
||||||
|
Ok(handle) => {
|
||||||
|
let res = ResHandle::<Model>::clone(&handle);
|
||||||
|
Ok(Self(ModelComponent(res)))
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
Err(elua::Error::BadArgument {
|
||||||
|
func: Some("ModelComponent:new".to_string()),
|
||||||
|
arg_index: 1,
|
||||||
|
arg_name: Some("model".to_string()),
|
||||||
|
error: Arc::new(
|
||||||
|
elua::Error::runtime("resource handle is not a handle to a Model")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
|
Ok(ScriptBorrow::from_component::<ModelComponent>(None))
|
||||||
|
}).method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
|
Ok(ScriptBorrow::from_component(Some(this.0.clone())))
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromLua<'a> for LuaModelComponent {
|
||||||
|
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("Model", &tyname))?;
|
||||||
|
let ud = ud.as_ref::<LuaModelComponent>()?;
|
||||||
|
|
||||||
|
Ok(ud.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaWrapper for LuaModelComponent {
|
||||||
|
fn wrapped_type_id() -> std::any::TypeId {
|
||||||
|
TypeId::of::<ModelComponent>()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
|
use elua::FromLua;
|
||||||
|
use lyra_resource::ResourceStorage;
|
||||||
|
|
||||||
|
#[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>(_: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||||
|
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())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue