From ef7b76ff39d501028852835649f618fcbe17a003 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 13 Apr 2024 17:38:45 +0200 Subject: feat(ecs): add extensions --- ecs/examples/extension.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++ ecs/src/extension.rs | 56 ++++++++++++++++++++++++++++++++++ ecs/src/lib.rs | 13 ++++++++ 3 files changed, 146 insertions(+) create mode 100644 ecs/examples/extension.rs create mode 100644 ecs/src/extension.rs diff --git a/ecs/examples/extension.rs b/ecs/examples/extension.rs new file mode 100644 index 0000000..2022b05 --- /dev/null +++ b/ecs/examples/extension.rs @@ -0,0 +1,77 @@ +use ecs::actions::Actions; +use ecs::event::Event; +use ecs::extension::{Collector as ExtensionCollector, Extension}; +use ecs::{Component, Query, World}; + +#[derive(Debug, Component)] +struct Position +{ + x: u32, + y: u32, +} + +#[derive(Debug, Component)] +struct EnemySpawnSource; + +#[derive(Debug, Component)] +enum EvilnessLevel +{ + Medium, +} + +#[derive(Debug)] +struct Update; + +impl Event for Update {} + +fn spawn_enemies( + spawner_query: Query<(EnemySpawnSource, Position)>, + enemies_query: Query<(EvilnessLevel,)>, + mut actions: Actions, +) +{ + let Some((_, enemy_spawner_position)) = spawner_query.iter().next() else { + return; + }; + + let enemy_cnt = enemies_query.iter().count(); + + if enemy_cnt > 3 { + return; + } + + actions.spawn(( + EvilnessLevel::Medium, + Position { + x: enemy_spawner_position.x * enemy_cnt as u32, + y: enemy_spawner_position.y, + }, + )); + + println!("Spawned enemy with medium evilness and 45 strength"); +} + +struct EnemySpawningExtension; + +impl Extension for EnemySpawningExtension +{ + fn collect(self, mut collector: ExtensionCollector<'_>) + { + collector.add_system(Update, spawn_enemies); + + collector.add_entity((Position { x: 187, y: 30 }, EnemySpawnSource)); + } +} + +fn main() +{ + let mut world = World::new(); + + world.add_extension(EnemySpawningExtension); + + for _ in 0..7 { + world.emit(Update); + + world.perform_queued_actions(); + } +} diff --git a/ecs/src/extension.rs b/ecs/src/extension.rs new file mode 100644 index 0000000..fc5a345 --- /dev/null +++ b/ecs/src/extension.rs @@ -0,0 +1,56 @@ +use crate::component::Sequence as ComponentSequence; +use crate::event::Event; +use crate::sole::Sole; +use crate::system::System; +use crate::{SoleAlreadyExistsError, World}; + +/// A collection of systems, entities & soles that can be added to a [`World`]. +pub trait Extension +{ + fn collect(self, collector: Collector<'_>); +} + +/// Passed to a [`Extension`] to collects it's systems, entities & soles. +pub struct Collector<'world> +{ + world: &'world mut World, +} + +impl<'world> Collector<'world> +{ + /// Returns a new `Collector` for the given [`World`]. + pub fn new(world: &'world mut World) -> Self + { + Self { world } + } + + /// Adds a system to the [`World`]. + pub fn add_system<'this, EventT, SystemImpl>( + &'this mut self, + event: EventT, + system: impl System<'this, SystemImpl>, + ) where + EventT: Event, + { + self.world.register_system(event, system); + } + + /// Adds a entity to the [`World`]. + pub fn add_entity(&mut self, components: Comps) + where + Comps: ComponentSequence, + { + self.world.create_entity(components); + } + + /// Adds a globally shared singleton value to the [`World`]. + /// + /// # Errors + /// Returns `Err` if this [`Sole`] has already been added. + pub fn add_sole(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> + where + SoleT: Sole, + { + self.world.add_sole(sole) + } +} diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 285f3b3..009ff21 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -12,6 +12,7 @@ use std::vec::Drain; use crate::actions::Action; use crate::component::{Component, Sequence as ComponentSequence}; use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence}; +use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::Lock; use crate::sole::Sole; use crate::system::{System, TypeErased as TypeErasedSystem}; @@ -20,6 +21,7 @@ use crate::type_name::TypeName; pub mod actions; pub mod component; pub mod event; +pub mod extension; pub mod lock; pub mod query; pub mod sole; @@ -120,6 +122,17 @@ impl World drop(event); } + /// Adds a extensions. + /// + /// # Panics + /// Will panic if mutable internal lock cannot be acquired. + pub fn add_extension(&mut self, extension: impl Extension) + { + let extension_collector = ExtensionCollector::new(self); + + extension.collect(extension_collector); + } + /// Emits a event, running all systems listening to the event for each compatible /// entity. /// -- cgit v1.2.3-18-g5258