bevy_scene_hook/
lib.rs

1//! Systems to insert components on loaded scenes.
2//!
3//! Hooks allow you to run code on a scene after loading it. It provides an API
4//! similar to the bevy [`SceneBundle`], but with the ability to add components
5//! to scene entities once they are loaded.
6//!
7//! This crate has two hook types:
8//! 1. The very basic [`SceneHook`], it has a `hook` function field. It will
9//!    run once per entity within the scene, with the ability to add new
10//!    components to the entity and read its existing components.
11//! 2. The more advanced [`reload::Hook`]. Which works like [`SceneHook`],
12//!    but is aware of **reload** state, and also has access to the ECS `&World`
13//!    and the root `Entity` of the scene it is running for.
14//!
15//! The the respective documentation of [`SceneHook`] and [`reload::Hook`] for
16//! usage examples.
17mod hook;
18pub mod reload;
19
20use bevy::{ecs::system::SystemParam, prelude::*, scene::scene_spawner_system};
21
22pub use hook::{run_hooks, SceneHook, SceneHooked};
23
24#[cfg(doctest)]
25#[doc = include_str!("../Readme.md")]
26pub struct TestReadme;
27
28/// Bundle a [`SceneHook`] with the standard [`SceneBundle`] components.
29///
30/// See [`HookedDynamicSceneBundle`] for dynamic scene support.
31#[derive(Bundle)]
32#[allow(missing_docs /* field description is trivial */)]
33pub struct HookedSceneBundle {
34    pub hook: SceneHook,
35    pub scene: SceneBundle,
36}
37
38/// Bundle a [`SceneHook`] with dynamic scenes [`DynamicSceneBundle`] components.
39///
40/// Similar to [`HookedSceneBundle`], but for dynamic scenes.
41#[derive(Bundle)]
42#[allow(missing_docs /* field description is trivial */)]
43pub struct HookedDynamicSceneBundle {
44    pub hook: SceneHook,
45    pub scene: DynamicSceneBundle,
46}
47
48/// Convenience parameter to query if a scene marked with `M` has been loaded.
49#[derive(SystemParam)]
50pub struct HookedSceneState<'w, 's, M: Component> {
51    query: Query<'w, 's, (), (With<M>, With<SceneHooked>)>,
52}
53impl<'w, 's, T: Component> HookedSceneState<'w, 's, T> {
54    /// Whether any scene with `T` component has been loaded and its hook ran.
55    #[must_use]
56    pub fn is_loaded(&self) -> bool {
57        self.query.iter().next().is_some()
58    }
59}
60
61/// Convenience run criteria to query if a scene marked with `M` has been loaded.
62#[allow(clippy::must_use_candidate)]
63pub fn is_scene_hooked<M: Component>(state: HookedSceneState<M>) -> bool {
64    state.is_loaded()
65}
66
67/// Systems defined in the [`bevy_scene_hook`](crate) crate (this crate).
68#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemSet)]
69pub enum Systems {
70    /// System running the hooks.
71    SceneHookRunner,
72}
73
74/// Plugin to run hooks associated with spawned scenes.
75pub struct HookPlugin;
76impl Plugin for HookPlugin {
77    fn build(&self, app: &mut App) {
78        app.add_systems(
79            SpawnScene,
80            run_hooks
81                .in_set(Systems::SceneHookRunner)
82                .after(scene_spawner_system),
83        );
84    }
85}