# Plugins, App, States, Schedules ## Plugin trait (`bevy::app::Plugin`) Required: - `fn build(&self, app: &mut App)` — runs immediately on `add_plugins`. Optional (defaults provided): - `fn ready(&self, _: &App) -> bool` — default `true`; override for async init. - `fn finish(&self, _: &mut App)` — runs after all plugins report `ready()`, before the first schedule tick. The idiomatic place for cross-plugin setup that needs another plugin's resources to exist. - `fn cleanup(&self, _: &mut App)` — runs after `finish()`; remove temp resources. - `fn name(&self) -> &str` — defaults to type name; used for the uniqueness check. - `fn is_unique(&self) -> bool` — default `true`; return `false` for multi-instance plugins. Any `fn(&mut App)` auto-implements `Plugin`. ## Plugin dependencies There is no formal depends-on declaration. Patterns: - `app.is_plugin_added::()` to guard or panic early with a clear message. - Sub-plugins: call `app.add_plugins(ChildPlugin)` inside `build()`. Bevy deduplicates by name; unique plugins panic on double-add. - Cross-plugin wiring that needs the other plugin's resources → `finish()`. ## Plugin groups `DefaultPlugins` / `MinimalPlugins` implement `PluginGroup`. Customize via the builder: ```rust DefaultPlugins .disable::() .set(WindowPlugin { /* config */ }) .add_before::(MyPlugin) ``` `.disable::()`, `.enable::()`, `.set(plugin)`, `.add_before::(p)`, `.add_after::(p)`. ## App builder key methods | Method | Purpose | |--------|---------| | `add_plugins(P)` | Plugin, plugin group, or tuple of either | | `insert_resource(R)` | Insert, overwriting existing | | `init_resource::()` | Insert via `Default`/`FromWorld` if absent | | `add_systems(schedule, systems)` | Add to a schedule | | `configure_sets(schedule, sets)` | Order system sets | | `register_type::()` | Reflection registry | | `is_plugin_added::()` | Plugin presence check | | `register_required_components::()` | Runtime component requirements | ## States Three flavors: - **FreelyMutableState** — changed via the `NextState` resource. - **SubStates** — exist only while the parent state is in a required variant. - **ComputedStates** — derived: `fn compute(sources) -> Option`. Registration: `app.init_state::()` (default initial) or `app.insert_state(value)`. Transition schedules: `OnEnter(S)`, `OnExit(S)`, `OnTransition(S)`. Entity scoping: `DespawnOnEnter(S)`, `DespawnOnExit(S)` (replaced `StateScoped`, 0.16+). Run condition: `in_state(S)`. **0.18 behavior change**: `NextState::set()` fires `OnExit`+`OnEnter` even when setting the current state. Use `set_if_neq()` for no-op-on-same. One-time setup in `OnEnter` systems will re-run if any caller `set()`s the active state. ## Schedules | Phase | Schedules | |-------|-----------| | Startup (once) | `PreStartup`, `Startup`, `PostStartup` | | Per-frame | `First`, `PreUpdate`, `Update`, `PostUpdate`, `Last` | | Fixed timestep | `FixedFirst`, `FixedPreUpdate`, `FixedUpdate`, `FixedPostUpdate`, `FixedLast` (inside `FixedMain`, driven by `RunFixedMainLoop`) | | Other | `Main`, `SpawnScene` | Gameplay simulation that must be framerate-independent goes in `FixedUpdate`. Transform propagation and most engine bookkeeping run in `PostUpdate`. ## Run conditions (`common_conditions`) - `in_state(s)` - `resource_exists::()`, `resource_added::()`, `resource_changed::()`, `resource_equals(val)` - `any_with_component::()`, `any_component_removed::()` - `on_message::()` (renamed from `on_event`, 0.18) - `run_once()`, `not(cond)`, `condition_changed(cond)`, `condition_changed_to(cond)` Combine with `.and(cond)` / `.or(cond)`.