diff --git a/.vscode/launch.json b/.vscode/launch.json index 238c8c0..a05d1f5 100755 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -72,7 +72,7 @@ "--no-run", "--lib", "--package=lyra-ecs", - "world::tests::view_change_tracking", + "command::tests::deferred_commands", "--", "--exact --nocapture" ], diff --git a/Cargo.lock b/Cargo.lock index 448879d..4f54a87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,7 +1456,6 @@ dependencies = [ "paste", "rand", "thiserror", - "unique", ] [[package]] @@ -1520,7 +1519,6 @@ dependencies = [ "lyra-ecs", "lyra-math", "lyra-reflect-derive", - "lyra-resource", ] [[package]] @@ -2688,12 +2686,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "unique" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d360722e1f3884f5b14d332185f02ff111f771f0c76a313268fe6af1409aba96" - [[package]] name = "urlencoding" version = "2.1.3" diff --git a/lyra-ecs/Cargo.toml b/lyra-ecs/Cargo.toml index fe1e97f..47643c8 100644 --- a/lyra-ecs/Cargo.toml +++ b/lyra-ecs/Cargo.toml @@ -13,7 +13,6 @@ lyra-ecs-derive = { path = "./lyra-ecs-derive" } lyra-math = { path = "../lyra-math", optional = true } anyhow = "1.0.75" thiserror = "1.0.50" -unique = "0.9.1" paste = "1.0.14" [dev-dependencies] diff --git a/lyra-ecs/src/command.rs b/lyra-ecs/src/command.rs index d487d7c..137f8f1 100644 --- a/lyra-ecs/src/command.rs +++ b/lyra-ecs/src/command.rs @@ -1,26 +1,30 @@ -use std::{cell::RefMut, collections::VecDeque, mem, ptr::{self, NonNull}}; - -use unique::Unique; +use std::{any::Any, cell::RefMut, collections::VecDeque, ptr::{self, NonNull}}; use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, World}; -pub trait Command { +pub trait Command: Any { + fn as_any_boxed(self: Box) -> Box; + fn run(self, world: &mut World) -> anyhow::Result<()>; } impl Command for F where - F: FnOnce(&mut World) -> anyhow::Result<()> + F: FnOnce(&mut World) -> anyhow::Result<()> + 'static { + fn as_any_boxed(self: Box) -> Box { + self + } + fn run(self, world: &mut World) -> anyhow::Result<()> { self(world) } } -type RunCommand = unsafe fn(cmd: Unique<()>, world: &mut World) -> anyhow::Result<()>; +type RunCommand = unsafe fn(cmd: Box, world: &mut World) -> anyhow::Result<()>; #[derive(Default)] -pub struct CommandQueue(VecDeque<(RunCommand, Unique<()>)>); +pub struct CommandQueue(VecDeque<(RunCommand, Box)>); pub struct Commands<'a, 'b> { queue: &'b mut CommandQueue, @@ -36,31 +40,26 @@ impl<'a, 'b> Commands<'a, 'b> { } /// Add a command to the end of the command queue - pub fn add(&mut self, mut cmd: C) { - // get an owned pointer to the command, then forget it to ensure its destructor isn't ran - let ptr = Unique::from(&mut cmd).cast::<()>(); - mem::forget(cmd); + pub fn add(&mut self, cmd: C) { + let cmd = Box::new(cmd); - let run_fn = |cmd_ptr: Unique<()>, world: &mut World| unsafe { - let cmd = cmd_ptr.cast::(); - let cmd = ptr::read(cmd.as_ptr()); + let run_fn = |cmd: Box, world: &mut World| { + let cmd = cmd.as_any_boxed() + .downcast::() + .unwrap(); + cmd.run(world)?; Ok(()) }; - self.queue.0.push_back((run_fn, ptr)); + self.queue.0.push_back((run_fn, cmd)); } - pub fn spawn(&mut self, mut bundle: B) -> Entity { + pub fn spawn(&mut self, bundle: B) -> Entity { 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| { - let bundle = unsafe { ptr::read(bundle_ptr.as_ptr()) }; world.spawn_into(e, bundle); Ok(()) }); @@ -101,7 +100,7 @@ impl FnArgFetcher for Commands<'_, '_> { let world = unsafe { world_ptr.as_mut() }; 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() }; cmds.execute(world).unwrap() } @@ -111,4 +110,41 @@ pub fn execute_deferred_commands(world: &mut World, mut commands: RefMut 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::()).unwrap(); + let vec2: &Vec2 = unsafe { col.get(3) }; + assert_eq!(vec2.clone(), spawned_vec); + } } \ No newline at end of file diff --git a/lyra-ecs/src/entity.rs b/lyra-ecs/src/entity.rs index 7fefa67..b12e04f 100644 --- a/lyra-ecs/src/entity.rs +++ b/lyra-ecs/src/entity.rs @@ -35,7 +35,6 @@ impl Entities { e } None => { - println!("id is {}", self.next_id.0); let new_id = self.next_id; 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 pub(crate) fn entity_record(&self, entity: Entity) -> Option { self.arch_index.get(&entity.id).cloned() diff --git a/lyra-ecs/src/system/fn_sys.rs b/lyra-ecs/src/system/fn_sys.rs index 4252db7..856ce16 100644 --- a/lyra-ecs/src/system/fn_sys.rs +++ b/lyra-ecs/src/system/fn_sys.rs @@ -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 crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery, ResMut, Res}}; @@ -12,7 +11,6 @@ pub trait FnArgFetcher { type Arg<'a, 'state>: FnArgFetcher; - //fn new() -> Self; fn create_state(world: NonNull) -> Self::State; /// Return the appropriate world access if this fetcher gets the world directly. @@ -40,7 +38,7 @@ pub struct FnSystem { inner: F, //#[allow(dead_code)] //args: Args, - arg_state: Option>>, + arg_state: Option>>, _marker: PhantomData, } @@ -60,10 +58,8 @@ macro_rules! impl_fn_system_tuple { paste! { $( // get the arg fetcher, create its state, and get the arg - let mut []: $name::State = $name::create_state(world); let [<$name:lower>] = $name::get(&mut [], world); - )+ (self.inner)($( [<$name:lower>] ),+)?; @@ -71,9 +67,8 @@ macro_rules! impl_fn_system_tuple { let mut state = Vec::new(); $( // type erase the now modified state, and store it - let [] = Unique::from(&mut []); - std::mem::forget([]); - state.push([].cast::<()>()); + let boxed = Box::new([]) as Box; + state.push(boxed); )+ self.arg_state = Some(state); @@ -84,41 +79,22 @@ macro_rules! impl_fn_system_tuple { } fn execute_deferred(&mut self, world: NonNull) -> 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 s = unsafe { std::ptr::read(s.cast::<$name::State>().as_ptr()) }; - $name::apply_deferred(s, world); + let arg_state_box = state.pop() + .expect("Missing expected arg state"); + let arg_state = *arg_state_box.downcast::<$name::State>() + .unwrap(); + $name::apply_deferred(arg_state, world); )+ Ok(()) } } - /* impl 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; - - fn into_system(self) -> Self::System { - FnSystem { - //args: ($($name::Fetcher::new(),)+), - inner: self, - arg_state: None, - _marker: PhantomData::<($($name::Fetcher,)+)>::default(), - } - } - } */ - impl 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::Arg<'a, '_>,)+) -> anyhow::Result<()>, { @@ -126,7 +102,6 @@ macro_rules! impl_fn_system_tuple { fn into_system(self) -> Self::System { FnSystem { - //args: ($($name::Fetcher::new(),)+), inner: self, arg_state: None, _marker: PhantomData::<($($name,)+)>::default(), diff --git a/lyra-ecs/src/world.rs b/lyra-ecs/src/world.rs index 9e56991..1c89301 100644 --- a/lyra-ecs/src/world.rs +++ b/lyra-ecs/src/world.rs @@ -93,7 +93,6 @@ impl World { let entity_arch_id = archetype.add_entity(entity, bundle, &tick); // store archetype - println!("About to store arch, cap is {}, len is {}", self.archetypes.capacity(), self.archetypes.len()); self.archetypes.insert(new_arch_id, archetype); // Create entity record and store it