|
1 | 1 | //! Dynamic scheduling from scripts
|
2 | 2 |
|
3 |
| -use std::{ |
4 |
| - any::TypeId, |
5 |
| - borrow::Cow, |
6 |
| - collections::HashMap, |
7 |
| - hash::Hash, |
8 |
| - ops::Deref, |
9 |
| - sync::{ |
10 |
| - atomic::{AtomicUsize, Ordering}, |
11 |
| - Arc, |
12 |
| - }, |
13 |
| -}; |
14 |
| - |
| 3 | +use super::{script_system::ScriptSystemBuilder, WorldAccessGuard}; |
| 4 | +use crate::{error::InteropError, IntoScriptPluginParams}; |
15 | 5 | use bevy::{
|
16 | 6 | app::{
|
17 | 7 | First, FixedFirst, FixedLast, FixedMain, FixedPostUpdate, FixedPreUpdate, FixedUpdate,
|
18 | 8 | Last, PostStartup, PostUpdate, PreStartup, PreUpdate, RunFixedMainLoop, Startup, Update,
|
19 | 9 | },
|
20 | 10 | ecs::{
|
21 |
| - entity::Entity, |
22 |
| - intern::Interned, |
23 |
| - schedule::{ |
24 |
| - InternedScheduleLabel, IntoSystemConfigs, NodeId, Schedule, ScheduleLabel, Schedules, |
25 |
| - SystemSet, |
26 |
| - }, |
27 |
| - system::{IntoSystem, Resource, System, SystemInput, SystemState}, |
| 11 | + schedule::{InternedScheduleLabel, NodeId, Schedule, ScheduleLabel, Schedules}, |
| 12 | + system::{Resource, System, SystemInput}, |
28 | 13 | world::World,
|
29 | 14 | },
|
30 | 15 | reflect::Reflect,
|
31 | 16 | };
|
32 | 17 | use parking_lot::RwLock;
|
33 |
| - |
34 |
| -use crate::{ |
35 |
| - error::InteropError, |
36 |
| - event::CallbackLabel, |
37 |
| - extractors::{HandlerContext, WithWorldGuard}, |
38 |
| - handler::handle_script_errors, |
39 |
| - script::ScriptId, |
40 |
| - IntoScriptPluginParams, |
41 |
| -}; |
42 |
| - |
43 |
| -use super::{WorldAccessGuard, WorldGuard}; |
| 18 | +use std::{any::TypeId, borrow::Cow, collections::HashMap, ops::Deref, sync::Arc}; |
44 | 19 |
|
45 | 20 | #[derive(Reflect, Debug, Clone)]
|
46 | 21 | /// A reflectable system.
|
47 | 22 | pub struct ReflectSystem {
|
48 |
| - name: Cow<'static, str>, |
49 |
| - type_id: TypeId, |
50 |
| - node_id: ReflectNodeId, |
| 23 | + pub(crate) name: Cow<'static, str>, |
| 24 | + pub(crate) type_id: TypeId, |
| 25 | + pub(crate) node_id: ReflectNodeId, |
51 | 26 | }
|
52 | 27 |
|
53 | 28 | #[derive(Reflect, Clone, Debug)]
|
54 | 29 | #[reflect(opaque)]
|
55 |
| -pub(crate) struct ReflectNodeId(pub(crate) NodeId); |
| 30 | +pub(crate) struct ReflectNodeId(pub NodeId); |
56 | 31 |
|
57 | 32 | impl ReflectSystem {
|
58 | 33 | /// Creates a reflect system from a system specification
|
@@ -230,177 +205,6 @@ impl ScheduleRegistry {
|
230 | 205 | }
|
231 | 206 | }
|
232 | 207 |
|
233 |
| -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] |
234 |
| -/// a system set for script systems. |
235 |
| -pub struct ScriptSystemSet(usize); |
236 |
| - |
237 |
| -impl ScriptSystemSet { |
238 |
| - /// Creates a new script system set with a unique id |
239 |
| - pub fn next() -> Self { |
240 |
| - static CURRENT_ID: AtomicUsize = AtomicUsize::new(0); |
241 |
| - Self(CURRENT_ID.fetch_add(1, Ordering::Relaxed)) |
242 |
| - } |
243 |
| -} |
244 |
| - |
245 |
| -impl SystemSet for ScriptSystemSet { |
246 |
| - fn dyn_clone(&self) -> bevy::ecs::label::Box<dyn SystemSet> { |
247 |
| - Box::new(*self) |
248 |
| - } |
249 |
| - |
250 |
| - fn as_dyn_eq(&self) -> &dyn bevy::ecs::label::DynEq { |
251 |
| - self |
252 |
| - } |
253 |
| - |
254 |
| - fn dyn_hash(&self, mut state: &mut dyn ::core::hash::Hasher) { |
255 |
| - self.hash(&mut state); |
256 |
| - } |
257 |
| -} |
258 |
| - |
259 |
| -/// A builder for systems living in scripts |
260 |
| -#[derive(Reflect)] |
261 |
| -pub struct ScriptSystemBuilder { |
262 |
| - name: CallbackLabel, |
263 |
| - script_id: ScriptId, |
264 |
| - before: Vec<ReflectSystem>, |
265 |
| - after: Vec<ReflectSystem>, |
266 |
| -} |
267 |
| - |
268 |
| -impl ScriptSystemBuilder { |
269 |
| - /// Creates a new script system builder |
270 |
| - pub fn new(name: CallbackLabel, script_id: ScriptId) -> Self { |
271 |
| - Self { |
272 |
| - before: vec![], |
273 |
| - after: vec![], |
274 |
| - name, |
275 |
| - script_id, |
276 |
| - } |
277 |
| - } |
278 |
| - |
279 |
| - /// Adds a system to run before the script system |
280 |
| - pub fn before(&mut self, system: ReflectSystem) -> &mut Self { |
281 |
| - self.before.push(system); |
282 |
| - self |
283 |
| - } |
284 |
| - |
285 |
| - /// Adds a system to run after the script system |
286 |
| - pub fn after(&mut self, system: ReflectSystem) -> &mut Self { |
287 |
| - self.after.push(system); |
288 |
| - self |
289 |
| - } |
290 |
| - |
291 |
| - /// Selects the most granual system set it can for the given system node id or None |
292 |
| - fn get_individual_system_system_set( |
293 |
| - node_id: NodeId, |
294 |
| - schedule: &Schedule, |
295 |
| - ) -> Option<Interned<dyn SystemSet>> { |
296 |
| - // if let Some(system) = schedule.graph().get_system_at(node_id) { |
297 |
| - // // this only works for normal bevy rust systems |
298 |
| - // if let Some(system_set) = system.default_system_sets().first() { |
299 |
| - // return Some(system_set.dyn_clone()); |
300 |
| - // } |
301 |
| - // } |
302 |
| - if let Ok(systems) = schedule.systems() { |
303 |
| - for (system_id, system) in systems { |
304 |
| - if system_id == node_id { |
305 |
| - return system.default_system_sets().first().cloned(); |
306 |
| - } |
307 |
| - } |
308 |
| - } |
309 |
| - |
310 |
| - None |
311 |
| - } |
312 |
| - |
313 |
| - /// Builds the system and inserts it into the given schedule |
314 |
| - #[allow(deprecated)] |
315 |
| - pub fn build<P: IntoScriptPluginParams>( |
316 |
| - self, |
317 |
| - world: WorldGuard, |
318 |
| - schedule: &ReflectSchedule, |
319 |
| - ) -> Result<ReflectSystem, InteropError> { |
320 |
| - world.scope_schedule(schedule, |world, schedule| { |
321 |
| - // this is different to a normal event handler |
322 |
| - // the system doesn't listen to events |
323 |
| - // it immediately calls a singular script with a predefined payload |
324 |
| - let system_name = format!("script_system_{}", &self.name); |
325 |
| - let _system = move |world: &mut World, |
326 |
| - system_state: &mut SystemState< |
327 |
| - WithWorldGuard<HandlerContext<P>>, |
328 |
| - >| { |
329 |
| - let mut with_guard = system_state.get_mut(world); |
330 |
| - |
331 |
| - { |
332 |
| - let (guard, handler_ctxt) = with_guard.get_mut(); |
333 |
| - let name = self.name.clone(); |
334 |
| - bevy::log::debug_once!("First call to script system {}", name); |
335 |
| - match handler_ctxt.call_dynamic_label( |
336 |
| - &name, |
337 |
| - &self.script_id, |
338 |
| - Entity::from_raw(0), |
339 |
| - vec![], |
340 |
| - guard.clone(), |
341 |
| - ) { |
342 |
| - Ok(_) => {} |
343 |
| - Err(err) => { |
344 |
| - handle_script_errors( |
345 |
| - guard, |
346 |
| - vec![err.with_script(self.script_id.clone())].into_iter(), |
347 |
| - ); |
348 |
| - } |
349 |
| - }; |
350 |
| - } |
351 |
| - |
352 |
| - system_state.apply(world); |
353 |
| - }; |
354 |
| - |
355 |
| - let function_system = IntoSystem::into_system(_system.clone()).with_name(system_name); |
356 |
| - |
357 |
| - // dummy node id for now |
358 |
| - let mut reflect_system = |
359 |
| - ReflectSystem::from_system(&function_system, NodeId::System(0)); |
360 |
| - |
361 |
| - // this is quite important, by default systems are placed in a set defined by their TYPE, i.e. in this case |
362 |
| - // all script systems would be the same |
363 |
| - let set = ScriptSystemSet::next(); |
364 |
| - let mut config = IntoSystemConfigs::into_configs(function_system.in_set(set)); |
365 |
| - |
366 |
| - // apply ordering |
367 |
| - for (other, is_before) in self |
368 |
| - .before |
369 |
| - .iter() |
370 |
| - .map(|b| (b, true)) |
371 |
| - .chain(self.after.iter().map(|a| (a, false))) |
372 |
| - { |
373 |
| - match Self::get_individual_system_system_set(other.node_id.0, schedule) { |
374 |
| - Some(set) => { |
375 |
| - if is_before { |
376 |
| - config = config.before(set); |
377 |
| - } else { |
378 |
| - config = config.after(set); |
379 |
| - } |
380 |
| - } |
381 |
| - None => { |
382 |
| - bevy::log::warn!( |
383 |
| - "Could not find system set for system {:?}", |
384 |
| - other.identifier() |
385 |
| - ); |
386 |
| - } |
387 |
| - } |
388 |
| - } |
389 |
| - |
390 |
| - schedule.configure_sets(set); |
391 |
| - schedule.add_systems(config); |
392 |
| - |
393 |
| - schedule.initialize(world)?; |
394 |
| - |
395 |
| - let node_id = NodeId::System(schedule.systems_len()); |
396 |
| - |
397 |
| - reflect_system.node_id = ReflectNodeId(node_id); |
398 |
| - |
399 |
| - Ok(reflect_system) |
400 |
| - })? |
401 |
| - } |
402 |
| -} |
403 |
| - |
404 | 208 | #[profiling::all_functions]
|
405 | 209 | /// Impls to do with dynamically querying systems and schedules
|
406 | 210 | impl WorldAccessGuard<'_> {
|
@@ -487,7 +291,7 @@ mod tests {
|
487 | 291 |
|
488 | 292 | use bevy::{
|
489 | 293 | app::{App, Update},
|
490 |
| - ecs::system::IntoSystem, |
| 294 | + ecs::{schedule::Schedules, system::IntoSystem}, |
491 | 295 | };
|
492 | 296 | use test_utils::make_test_plugin;
|
493 | 297 |
|
|
0 commit comments