summaryrefslogtreecommitdiff
path: root/ecs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-02-21 23:54:37 +0100
committerHampusM <hampus@hampusmat.com>2024-02-22 19:27:52 +0100
commit9f65dba3afd4e8f20881914fc86fa997cb64a13d (patch)
treed760f8f478af6591648ef3f53d4e0cb34ee76908 /ecs
parentb0ef7f2cf8787c5732e0eb5554161ad75179a4b3 (diff)
feat(ecs): add support for system local components
Diffstat (limited to 'ecs')
-rw-r--r--ecs/examples/with_local.rs76
-rw-r--r--ecs/src/component.rs34
-rw-r--r--ecs/src/system.rs24
-rw-r--r--ecs/src/system/stateful.rs67
4 files changed, 199 insertions, 2 deletions
diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs
new file mode 100644
index 0000000..d7af0e0
--- /dev/null
+++ b/ecs/examples/with_local.rs
@@ -0,0 +1,76 @@
+use ecs::component::Local;
+use ecs::system::{Into, System};
+use ecs::{Query, World};
+
+struct SomeData
+{
+ num: u64,
+}
+
+struct Name
+{
+ name: String,
+}
+
+struct SayHelloState
+{
+ cnt: usize,
+}
+
+fn say_hello(mut query: Query<(SomeData, String)>, mut state: Local<SayHelloState>)
+{
+ for (data, text) in query.iter_mut() {
+ println!("Hello there. Count {}: {}: {}", state.cnt, text, data.num);
+
+ state.cnt += 1;
+ }
+}
+
+fn say_whats_up(mut query: Query<(SomeData, Name)>, mut state: Local<SayHelloState>)
+{
+ for (data, name) in query.iter_mut() {
+ println!(
+ "Whats up, {}. Number is {}. Count {}",
+ name.name, data.num, state.cnt
+ );
+
+ state.cnt += 1;
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Hash)]
+enum Event
+{
+ Update,
+}
+
+fn main()
+{
+ let mut world = World::<Event>::new();
+
+ world.register_system(
+ Event::Update,
+ say_hello.into_system().initialize(SayHelloState { cnt: 0 }),
+ );
+
+ world.register_system(
+ Event::Update,
+ say_whats_up
+ .into_system()
+ .initialize(SayHelloState { cnt: 0 }),
+ );
+
+ world.create_entity((
+ SomeData { num: 987_654 },
+ "Yoo".to_string(),
+ Name { name: "Bob".to_string() },
+ ));
+
+ world.create_entity((SomeData { num: 345 }, "Haha".to_string()));
+
+ world.emit(&Event::Update);
+
+ println!("Haha");
+
+ world.emit(&Event::Update);
+}
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 4829050..8119e93 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -1,5 +1,6 @@
use std::any::{Any, TypeId};
use std::fmt::Debug;
+use std::ops::{Deref, DerefMut};
use seq_macro::seq;
@@ -112,3 +113,36 @@ macro_rules! inner {
seq!(C in 0..=64 {
inner!(C);
});
+
+/// Holds a component which is local to a single system.
+#[derive(Debug)]
+pub struct Local<'world, Value>
+{
+ value: &'world mut Value,
+}
+
+impl<'world, Value> Local<'world, Value>
+{
+ pub(crate) fn new(value: &'world mut Value) -> Self
+ {
+ Self { value }
+ }
+}
+
+impl<'world, Value> Deref for Local<'world, Value>
+{
+ type Target = Value;
+
+ fn deref(&self) -> &Self::Target
+ {
+ self.value
+ }
+}
+
+impl<'world, Value> DerefMut for Local<'world, Value>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target
+ {
+ &mut self.value
+ }
+}
diff --git a/ecs/src/system.rs b/ecs/src/system.rs
index ecf1885..8f4d0b0 100644
--- a/ecs/src/system.rs
+++ b/ecs/src/system.rs
@@ -1,14 +1,21 @@
use std::any::Any;
+use std::convert::Infallible;
use std::fmt::Debug;
use crate::component::Sequence as ComponentSequence;
use crate::{ComponentStorage, Query};
+pub mod stateful;
+
pub trait System<Impl>: 'static
{
type Query<'a>;
- fn run(&self, component_storage: &mut ComponentStorage);
+ type Input;
+
+ fn initialize(self, input: Self::Input) -> Self;
+
+ fn run(&mut self, component_storage: &mut ComponentStorage);
fn into_type_erased(self) -> TypeErased;
}
@@ -18,9 +25,15 @@ where
Func: Fn(Query<Comps>) + 'static,
Comps: ComponentSequence,
{
+ type Input = Infallible;
type Query<'a> = Query<'a, Comps>;
- fn run(&self, component_storage: &mut ComponentStorage)
+ fn initialize(self, _input: Self::Input) -> Self
+ {
+ self
+ }
+
+ fn run(&mut self, component_storage: &mut ComponentStorage)
{
self(Query::new(component_storage));
}
@@ -38,6 +51,13 @@ where
}
}
+pub trait Into<Impl>
+{
+ type System;
+
+ fn into_system(self) -> Self::System;
+}
+
pub struct TypeErased
{
data: Box<dyn Any>,
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
new file mode 100644
index 0000000..b641cf2
--- /dev/null
+++ b/ecs/src/system/stateful.rs
@@ -0,0 +1,67 @@
+use std::marker::PhantomData;
+
+use crate::component::Local;
+use crate::system::{System, TypeErased};
+use crate::{ComponentStorage, Query};
+
+/// A stateful system.
+pub struct Stateful<Func, LocalComponent, Comps>
+{
+ func: Func,
+ local_component: Option<LocalComponent>,
+ _comps_pd: PhantomData<Comps>,
+}
+
+impl<Func: 'static, Comps: 'static, LocalComponent: 'static>
+ System<fn(Query<Comps>, Local<LocalComponent>)>
+ for Stateful<Func, LocalComponent, Comps>
+where
+ Func: Fn(Query<Comps>, Local<LocalComponent>),
+{
+ type Input = LocalComponent;
+ type Query<'a> = Query<'a, Comps>;
+
+ fn initialize(mut self, input: Self::Input) -> Self
+ {
+ self.local_component = Some(input);
+
+ self
+ }
+
+ fn run(&mut self, component_storage: &mut ComponentStorage)
+ {
+ (self.func)(
+ Query::new(component_storage),
+ Local::new(self.local_component.as_mut().unwrap()),
+ );
+ }
+
+ fn into_type_erased(self) -> TypeErased
+ {
+ TypeErased {
+ data: Box::new(self),
+ func: Box::new(move |data, component_storage| {
+ let this = data.downcast_mut::<Self>().unwrap();
+
+ this.run(component_storage);
+ }),
+ }
+ }
+}
+
+impl<Func: 'static, Comps, LocalComponent: 'static>
+ crate::system::Into<fn(Query<Comps>, Local<LocalComponent>)> for Func
+where
+ Func: Fn(Query<Comps>, Local<LocalComponent>),
+{
+ type System = Stateful<Func, LocalComponent, Comps>;
+
+ fn into_system(self) -> Self::System
+ {
+ Self::System {
+ func: self,
+ local_component: None,
+ _comps_pd: PhantomData,
+ }
+ }
+}