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}