diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2b596a85e8..5d9ec293b2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog][kc], and this project adheres to ### Added +* `SystemExtra::enabled_on` for better support when enabling systems ([#1146]). * `amethyst_test` test framework for ergonomic testing of Amethyst applications ([#1000]) * combinations of buttons triggering actions ([#1043]) * `UiPrefab` field `hidden: bool` to hide entities ([#1051]) @@ -41,6 +42,7 @@ The format is based on [Keep a Changelog][kc], and this project adheres to ### Fixed +[#1146]: https://github.com/amethyst/amethyst/pull/1146 [#1000]: https://github.com/amethyst/amethyst/pull/1000 [#1043]: https://github.com/amethyst/amethyst/pull/1043 [#1051]: https://github.com/amethyst/amethyst/pull/1051 diff --git a/src/lib.rs b/src/lib.rs index 7afdfcbdcc..cd942d2398 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,3 +117,4 @@ mod game_data; mod logger; mod state; mod state_event; +mod system_extra; diff --git a/src/prelude.rs b/src/prelude.rs index 1609a2a395..c4c4bfb405 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -11,4 +11,5 @@ pub use { EmptyState, EmptyTrans, SimpleState, SimpleTrans, State, StateData, Trans, TransEvent, }, state_event::StateEvent, + system_extra::SystemExtra, }; diff --git a/src/system_extra.rs b/src/system_extra.rs new file mode 100644 index 0000000000..c11bcbf9c9 --- /dev/null +++ b/src/system_extra.rs @@ -0,0 +1,105 @@ +//! Extra system utilities. +//! +//! This modules contains an extension trait for the System trait which adds useful transformation +//! functions. + +use ecs::prelude::{Read, System}; +use shred::{RunningTime, SystemData}; + +/// Extra functionality associated systems. +pub trait SystemExtra { + /// Build a system that will do nothing unless the `V` resource the specified value. + /// + /// # Examples + /// + /// ```rust + /// use amethyst::{ + /// ecs::{System, Write}, + /// shred::DispatcherBuilder, + /// prelude::*, + /// }; + /// + /// #[derive(PartialEq, Eq)] + /// enum State { + /// Other, + /// Example, + /// } + /// + /// impl Default for State { + /// fn default() -> Self { + /// State::Other + /// } + /// } + /// + /// struct Example(u32); + /// + /// impl<'s> System<'s> for Example { + /// type SystemData = Write<'s, u32>; + /// + /// fn run(&mut self, mut number: Self::SystemData) { + /// *number = self.0; + /// } + /// } + /// + /// let mut world = World::new(); + /// + /// let mut dispatcher = DispatcherBuilder::default() + /// .with(Example(42), "set_number", &[]) + /// .with(Example(84).enabled_on(State::Example), "set_number_2", &[]) + /// .build(); + /// + /// dispatcher.setup(&mut world.res); + /// + /// // we only expect the u32 resource to be modified _if_ the system is enabled, + /// // the system should only be enabled on State::Example. + /// + /// *world.write_resource() = 1u32; + /// dispatcher.dispatch(&mut world.res); + /// assert_eq!(42, *world.read_resource::()); + /// + /// *world.write_resource::() = State::Example; + /// dispatcher.dispatch(&mut world.res); + /// assert_eq!(84, *world.read_resource::()); + /// ``` + fn enabled_on(self, value: V) -> EnabledOn + where + Self: Sized, + V: Send + Sync + Default + Eq; +} + +impl<'s, S> SystemExtra for S +where + S: System<'s>, +{ + fn enabled_on(self, value: V) -> EnabledOn + where + Self: Sized, + V: Send + Sync + Default + Eq, + { + EnabledOn(self, value) + } +} + +/// A system that is enabled when `U` has a specific value. +pub struct EnabledOn(S, V); + +impl<'s, S, V: 'static> System<'s> for EnabledOn +where + S::SystemData: SystemData<'s>, + S: System<'s>, + V: Send + Sync + Default + Eq, +{ + type SystemData = (Read<'s, V>, S::SystemData); + + fn run(&mut self, data: Self::SystemData) { + if self.1 != *data.0 { + return; + } + + self.0.run(data.1); + } + + fn running_time(&self) -> RunningTime { + self.0.running_time() + } +}