1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
//! Extension system utilities. //! //! This modules contains an extension trait for the System trait which adds useful transformation //! functions. use crate::{ ecs::prelude::{Read, System}, shred::{RunningTime, SystemData}, }; #[cfg(feature = "profiler")] use thread_profiler::profile_scope; /// Extension functionality associated systems. pub trait SystemExt { /// Make a system pausable by tying it to a specific value of a resource. /// /// When the value of the resource differs from `value` the system is considered "paused", /// and the `run` method of the pausable system will not be called. /// /// # Notes /// /// Special care must be taken not to read from an `EventChannel` with pausable systems. /// Since `run` is never called, there is no way to consume the reader side of a channel, and /// it may grow indefinitely leaking memory while the system is paused. /// /// # Examples /// /// ```rust /// use amethyst::{ /// ecs::{System, Write}, /// shred::DispatcherBuilder, /// prelude::*, /// }; /// /// #[derive(PartialEq)] /// enum CurrentState { /// Disabled, /// Enabled, /// } /// /// impl Default for CurrentState { /// fn default() -> Self { /// CurrentState::Disabled /// } /// } /// /// struct AddNumber(u32); /// /// impl<'s> System<'s> for AddNumber { /// 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(AddNumber(1), "set_number", &[]) /// .with(AddNumber(2).pausable(CurrentState::Enabled), "set_number_2", &[]) /// .build(); /// /// dispatcher.setup(&mut world); /// /// // we only expect the u32 resource to be modified _if_ the system is enabled, /// // the system should only be enabled on CurrentState::Enabled. /// /// *world.write_resource() = 0u32; /// dispatcher.dispatch(&mut world); /// assert_eq!(1, *world.read_resource::<u32>()); /// /// *world.write_resource() = 0u32; /// *world.write_resource() = CurrentState::Enabled; /// dispatcher.dispatch(&mut world); /// assert_eq!(1 + 2, *world.read_resource::<u32>()); /// ``` fn pausable<V: 'static>(self, value: V) -> Pausable<Self, V> where Self: Sized, V: Send + Sync + Default + PartialEq; } impl<'s, S> SystemExt for S where S: System<'s>, { fn pausable<V: 'static>(self, value: V) -> Pausable<Self, V> where Self: Sized, V: Send + Sync + Default + PartialEq, { Pausable { system: self, value, } } } /// A system that is enabled when `V` has a specific value. /// /// This is created using the [`SystemExt::pausable`] method. /// /// [`SystemExt::pausable`]: trait.SystemExt.html#tymethod.pausable #[derive(Debug)] pub struct Pausable<S, V> { system: S, value: V, } impl<'s, S, V: 'static> System<'s> for Pausable<S, V> where S::SystemData: SystemData<'s>, S: System<'s>, V: Send + Sync + Default + PartialEq, { type SystemData = (Read<'s, V>, S::SystemData); fn run(&mut self, data: Self::SystemData) { #[cfg(feature = "profiler")] profile_scope!("pauseable_system"); if self.value != *data.0 { return; } self.system.run(data.1); } fn running_time(&self) -> RunningTime { self.system.running_time() } }