diff options
author | HampusM <hampus@hampusmat.com> | 2024-04-06 12:30:49 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-04-06 13:44:26 +0200 |
commit | 519a73f83848ea668fe79895e6643cff4c5c51be (patch) | |
tree | 23e52eac67f80241f4efe590a05c17d489d48a2b | |
parent | 3e6d04be56e910f77048442a3c744298ef856ca1 (diff) |
feat(ecs): add stopping event loop
-rw-r--r-- | ecs/examples/event_loop.rs | 115 | ||||
-rw-r--r-- | ecs/src/flags.rs | 66 | ||||
-rw-r--r-- | ecs/src/lib.rs | 26 |
3 files changed, 207 insertions, 0 deletions
diff --git a/ecs/examples/event_loop.rs b/ecs/examples/event_loop.rs new file mode 100644 index 0000000..f9fd85f --- /dev/null +++ b/ecs/examples/event_loop.rs @@ -0,0 +1,115 @@ +use ecs::event::{Event, Id as EventId}; +use ecs::flags::Flags; +use ecs::{Component, Query, World}; + +#[derive(Component)] +struct Wool +{ + remaining: u32, +} + +#[derive(Component)] +struct Health +{ + health: u32, +} + +#[derive(Component)] +struct Name +{ + name: &'static str, +} + +fn sheer(query: Query<(Wool, Name)>) +{ + for (mut wool, name) in &query { + if wool.remaining == 0 { + println!("{} Has no wool left", name.name); + + continue; + } + + // Sheer the whool + wool.remaining -= 5; + + println!("Sheered 5 wool from {}", name.name); + } +} + +fn feed(query: Query<(Health, Name)>) +{ + for (mut health, name) in &query { + health.health += 1; + + println!("Feeded {} which gained 1 health", name.name); + } +} + +fn age(query: Query<(Health, Name)>, mut flags: Flags) +{ + for (mut health, name) in &query { + if health.health <= 2 { + health.health = 0; + + println!("{} passed away", name.name); + + flags.stop(); + + continue; + } + + health.health -= 2; + + println!("{} aged and lost 2 health", name.name); + } +} + +#[derive(Debug)] +struct EventA; + +impl Event for EventA +{ + fn id(&self) -> EventId + { + EventId::of::<Self>() + } +} + +#[derive(Debug)] +struct EventB; + +impl Event for EventB +{ + fn id(&self) -> EventId + { + EventId::of::<Self>() + } +} + +#[derive(Debug)] +struct EventC; + +impl Event for EventC +{ + fn id(&self) -> EventId + { + EventId::of::<Self>() + } +} + +fn main() +{ + let mut world = World::new(); + + world.register_system(&EventA, sheer); + world.register_system(&EventB, feed); + world.register_system(&EventC, age); + + world.create_entity(( + Wool { remaining: 30 }, + Health { health: 3 }, + Name { name: "Bessy" }, + )); + + world.event_loop::<(EventA, EventB, EventC)>(); +} diff --git a/ecs/src/flags.rs b/ecs/src/flags.rs new file mode 100644 index 0000000..ad10a0f --- /dev/null +++ b/ecs/src/flags.rs @@ -0,0 +1,66 @@ +use std::any::Any; + +use crate::lock::WriteGuard; +use crate::system::{ + NoInitParamFlag as NoInitSystemParamFlag, + Param as SystemParam, + System, +}; +use crate::tuple::FilterExclude as TupleFilterExclude; +use crate::{WorldData, WorldFlags}; + +#[derive(Debug)] +pub struct Flags<'world> +{ + world_flags: WriteGuard<'world, WorldFlags>, +} + +impl<'world> Flags<'world> +{ + /// Calling this function makes the loop in [`Engine::event_loop`] stop at the next + /// opportune time. + pub fn stop(&mut self) + { + self.world_flags.stop = true; + } +} + +unsafe impl<'world> SystemParam<'world> for Flags<'world> +{ + type Flags = NoInitSystemParamFlag; + type Input = TupleFilterExclude; + + fn initialize<SystemImpl>( + _system: &mut impl System<'world, SystemImpl>, + _input: Self::Input, + ) + { + } + + fn new<SystemImpl>( + _system: &'world impl System<'world, SystemImpl>, + world_data: &'world WorldData, + ) -> Self + { + Self { + world_flags: world_data + .flags + .write_nonblock() + .expect("Failed to acquire read-write world flags lock"), + } + } + + fn is_compatible<Other: SystemParam<'world>>() -> bool + { + let other_comparable = Other::get_comparable(); + + other_comparable.downcast_ref::<Comparable>().is_none() + } + + fn get_comparable() -> Box<dyn Any> + { + Box::new(Comparable) + } +} + +struct Comparable; diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 339a314..fc97d42 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -26,6 +26,7 @@ use crate::type_name::TypeName; pub mod actions; pub mod component; pub mod event; +pub mod flags; pub mod lock; pub mod system; pub mod tuple; @@ -166,6 +167,16 @@ impl World } self.perform_queued_actions(); + + let flags = self + .data + .flags + .read_nonblock() + .expect("Failed to aquire lock to flags"); + + if flags.stop { + break; + } } } @@ -187,11 +198,26 @@ impl World } #[derive(Debug, Default)] +struct WorldFlags +{ + stop: bool, +} + +impl TypeName for WorldFlags +{ + fn type_name(&self) -> &'static str + { + type_name::<Self>() + } +} + +#[derive(Debug, Default)] pub struct WorldData { events: HashMap<EventId, Vec<usize>>, component_storage: Arc<Lock<ComponentStorage>>, action_queue: Lock<ActionQueue>, + flags: Lock<WorldFlags>, } #[derive(Debug, Default)] |