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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
//local shortcuts
use crate::prelude::*;
//third-party shortcuts
use bevy::ecs::system::Command;
use bevy::prelude::*;
//standard shortcuts
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
fn end_system_event(world: &mut World)
{
let data_entity = world.resource_mut::<SystemEventAccessTracker>().end();
world.despawn(data_entity);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
fn end_entity_reaction(world: &mut World)
{
world.resource_mut::<EntityReactionAccessTracker>().end();
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
fn end_despawn_reaction(world: &mut World)
{
world.resource_mut::<DespawnAccessTracker>().end();
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
fn end_event(world: &mut World)
{
world.resource_mut::<EventAccessTracker>().end();
// note: cleanup is end_event_with_cleanup()
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
fn end_event_with_cleanup(world: &mut World)
{
let data_entity = world.resource_mut::<EventAccessTracker>().end();
world.despawn(data_entity);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
/// A system command.
///
/// System commands are stored on entities and must be manually scheduled with
/// [`command.apply()`](bevy::ecs::system::Command::apply) or
/// [`commands.send_system_event()`](super::ReactCommandsExt::send_system_event).
///
/// You can spawn your own system command with
/// [`commands.spawn_system_command()`](super::ReactCommandsExt::spawn_system_command).
///
/// All reactors are stored as system commands (i.e. systems registered with [`ReactCommands::on`]).
///
/// If scheduled as a [`Command`](bevy::ecs::system::Command) from user-land, this will cause a [`reaction_tree()`] to
/// execute, otherwise it will be processed within the already-running reaction tree.
#[derive(Debug, Copy, Clone, Deref)]
pub struct SystemCommand(pub Entity);
impl SystemCommand
{
pub(crate) fn run(self, world: &mut World)
{
syscommand_runner(world, self, SystemCommandCleanup::default());
}
}
impl Command for SystemCommand
{
fn apply(self, world: &mut World)
{
world.resource_mut::<CobwebCommandQueue<SystemCommand>>().push(self);
reaction_tree(world);
}
}
//-------------------------------------------------------------------------------------------------------------------
/// A system event command.
///
/// System events are sent with [`commands.send_system_event()`](super::ReactCommandsExt::send_system_event).
///
/// If scheduled as a `Command` from user-land, this will cause a [`reaction_tree()`] to execute, otherwise it will be
/// processed within the already-running reaction tree.
#[derive(Debug, Copy, Clone)]
pub(crate) struct EventCommand
{
/// The system command triggered by this event.
pub(crate) system: SystemCommand,
/// Entity where the event data is stored.
///
/// This entity will despawned in the system command cleanup callback.
pub(crate) data_entity: Entity,
}
impl EventCommand
{
/// Runs this event command on the world.
pub(crate) fn run(self, world: &mut World)
{
world.resource_mut::<SystemEventAccessTracker>().start(self.data_entity);
syscommand_runner(world, self.system, SystemCommandCleanup::new(end_system_event));
}
}
impl Command for EventCommand
{
fn apply(self, world: &mut World)
{
world.resource_mut::<CobwebCommandQueue<EventCommand>>().push(self);
reaction_tree(world);
}
}
//-------------------------------------------------------------------------------------------------------------------
/// A reaction command.
///
/// Reaction commands are sent by the internals of [`ReactCommands`].
///
/// If scheduled as a `Command` from user-land, this will cause a [`reaction_tree()`] to execute, otherwise it will be
/// processed within the already-running reaction tree.
#[derive(Clone)]
pub(crate) enum ReactionCommand
{
/// A reaction to a resource mutation.
Resource
{
/// The system command triggered by this event.
reactor: SystemCommand,
},
/// A reaction to an entity mutation.
EntityReaction
{
/// The entity that triggered this reaction.
reaction_source: Entity,
/// The type of the entity reaction trigger.
reaction_type: EntityReactionType,
/// The system command triggered by this event.
reactor: SystemCommand,
},
/// A reaction to an entity despawn.
Despawn
{
/// The entity that triggered this reaction.
reaction_source: Entity,
/// The system command triggered by this event.
reactor: SystemCommand,
/// A despawn handle for the reactor.
///
/// This will be dropped after the reactor runs, ensuring the reactor will be cleaned up if there are
/// no other owners of the handle.
handle: AutoDespawnSignal,
},
/// A reaction to an event (can be a broadcasted event or an entity event).
Event
{
/// Entity where the event data is stored.
data_entity: Entity,
/// The system command triggered by this event.
reactor: SystemCommand,
/// True if this is the last reaction that will read this event.
///
/// The `data_entity` will despawned in the system command cleanup callback if this is true.
last_reader: bool,
},
}
impl ReactionCommand
{
/// Runs the reaction on the world.
pub(crate) fn run(self, world: &mut World)
{
match self
{
Self::Resource{ reactor } =>
{
syscommand_runner(world, reactor, SystemCommandCleanup::default());
}
Self::EntityReaction{ reaction_source, reaction_type, reactor } =>
{
world.resource_mut::<EntityReactionAccessTracker>().start(reaction_source, reaction_type);
syscommand_runner(world, reactor, SystemCommandCleanup::new(end_entity_reaction));
}
Self::Despawn{ reaction_source, reactor, handle } =>
{
world.resource_mut::<DespawnAccessTracker>().start(reaction_source, handle);
syscommand_runner(world, reactor, SystemCommandCleanup::new(end_despawn_reaction));
}
Self::Event{ data_entity, reactor, last_reader } =>
{
world.resource_mut::<EventAccessTracker>().start(data_entity);
let cleanup = if last_reader { end_event_with_cleanup } else { end_event };
syscommand_runner(world, reactor, SystemCommandCleanup::new(cleanup));
}
}
}
}
impl Command for ReactionCommand
{
fn apply(self, world: &mut World)
{
world.resource_mut::<CobwebCommandQueue<ReactionCommand>>().push(self);
reaction_tree(world);
}
}
//-------------------------------------------------------------------------------------------------------------------