|
1 |
| -use bevy_ecs::system::{Commands, SystemId, SystemInput}; |
2 |
| -use bevy_ecs::world::{DeferredWorld, World}; |
| 1 | +use bevy_ecs::component::Component; |
| 2 | +use bevy_ecs::lifecycle::HookContext; |
| 3 | +use bevy_ecs::system::{Commands, EntityCommands, IntoSystem, SystemId, SystemInput}; |
| 4 | +use bevy_ecs::world::{DeferredWorld, EntityWorldMut, World}; |
3 | 5 |
|
4 | 6 | /// A callback defines how we want to be notified when a widget changes state. Unlike an event
|
5 | 7 | /// or observer, callbacks are intended for "point-to-point" communication that cuts across the
|
@@ -111,3 +113,100 @@ impl Notify for DeferredWorld<'_> {
|
111 | 113 | }
|
112 | 114 | }
|
113 | 115 | }
|
| 116 | + |
| 117 | +/// A component that hangs on to a registered one-shot system, and unregisters it when the |
| 118 | +/// component is despawned. |
| 119 | +#[derive(Component)] |
| 120 | +#[component(on_remove = on_despawn_callback_owner::<I>, storage = "SparseSet")] |
| 121 | +pub struct OwnedCallbackSystem<I: SystemInput + Send>(SystemId<I, ()>); |
| 122 | + |
| 123 | +fn on_despawn_callback_owner<I: SystemInput + Send + 'static>( |
| 124 | + mut world: DeferredWorld, |
| 125 | + context: HookContext, |
| 126 | +) { |
| 127 | + let system_id = world |
| 128 | + .entity(context.entity) |
| 129 | + .get::<OwnedCallbackSystem<I>>() |
| 130 | + .unwrap() |
| 131 | + .0; |
| 132 | + world.commands().unregister_system(system_id); |
| 133 | +} |
| 134 | + |
| 135 | +/// Methods for registering scoped callbacks. |
| 136 | +pub trait RegisterOwnedCallback { |
| 137 | + /// Registers a scoped one-shot system, with no input, that will be removed when the parent |
| 138 | + /// entity is despawned. |
| 139 | + fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>( |
| 140 | + &mut self, |
| 141 | + callback: I, |
| 142 | + ) -> Callback; |
| 143 | + |
| 144 | + /// Registers a scoped one-shot systemm, with input, that will be removed when the |
| 145 | + /// parent entity is despawned. |
| 146 | + fn register_owned_callback_with< |
| 147 | + M, |
| 148 | + A: SystemInput + Send + 'static, |
| 149 | + I: IntoSystem<A, (), M> + 'static, |
| 150 | + >( |
| 151 | + &mut self, |
| 152 | + callback: I, |
| 153 | + ) -> Callback<A>; |
| 154 | +} |
| 155 | + |
| 156 | +impl RegisterOwnedCallback for EntityCommands<'_> { |
| 157 | + fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>( |
| 158 | + &mut self, |
| 159 | + callback: I, |
| 160 | + ) -> Callback { |
| 161 | + let system_id = self.commands().register_system(callback); |
| 162 | + let owner = self.id(); |
| 163 | + self.commands() |
| 164 | + .spawn((OwnedCallbackSystem(system_id), crate::owner::OwnedBy(owner))); |
| 165 | + Callback::System(system_id) |
| 166 | + } |
| 167 | + |
| 168 | + fn register_owned_callback_with< |
| 169 | + M, |
| 170 | + A: SystemInput + Send + 'static, |
| 171 | + I: IntoSystem<A, (), M> + 'static, |
| 172 | + >( |
| 173 | + &mut self, |
| 174 | + callback: I, |
| 175 | + ) -> Callback<A> { |
| 176 | + let owner = self.id(); |
| 177 | + let system_id = self.commands().register_system(callback); |
| 178 | + self.commands() |
| 179 | + .spawn((OwnedCallbackSystem(system_id), crate::owner::OwnedBy(owner))); |
| 180 | + Callback::System(system_id) |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +impl RegisterOwnedCallback for EntityWorldMut<'_> { |
| 185 | + fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>( |
| 186 | + &mut self, |
| 187 | + callback: I, |
| 188 | + ) -> Callback { |
| 189 | + let owner = self.id(); |
| 190 | + let system_id = self.world_scope(|world| world.register_system(callback)); |
| 191 | + self.world_scope(|world| { |
| 192 | + world.spawn((OwnedCallbackSystem(system_id), crate::owner::OwnedBy(owner))); |
| 193 | + }); |
| 194 | + Callback::System(system_id) |
| 195 | + } |
| 196 | + |
| 197 | + fn register_owned_callback_with< |
| 198 | + M, |
| 199 | + A: SystemInput + Send + 'static, |
| 200 | + I: IntoSystem<A, (), M> + 'static, |
| 201 | + >( |
| 202 | + &mut self, |
| 203 | + callback: I, |
| 204 | + ) -> Callback<A> { |
| 205 | + let owner = self.id(); |
| 206 | + let system_id = self.world_scope(|world| world.register_system(callback)); |
| 207 | + self.world_scope(|world| { |
| 208 | + world.spawn((OwnedCallbackSystem(system_id), crate::owner::OwnedBy(owner))); |
| 209 | + }); |
| 210 | + Callback::System(system_id) |
| 211 | + } |
| 212 | +} |
0 commit comments