summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-04-06 12:30:49 +0200
committerHampusM <hampus@hampusmat.com>2024-04-06 13:44:26 +0200
commit519a73f83848ea668fe79895e6643cff4c5c51be (patch)
tree23e52eac67f80241f4efe590a05c17d489d48a2b
parent3e6d04be56e910f77048442a3c744298ef856ca1 (diff)
feat(ecs): add stopping event loop
-rw-r--r--ecs/examples/event_loop.rs115
-rw-r--r--ecs/src/flags.rs66
-rw-r--r--ecs/src/lib.rs26
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)]