Files
reliquary/plugins/bevy/skills/bevy-0.19/references/plugins-and-app.md
T
g4borg c661027d19 🤖 Flesh out bevy-0.19 and bevy-upgrade skills from research
Replace scaffold placeholders with full skill content:
- bevy-0.19: ECS cheat sheet, critical traps table, architecture guide, and 7 reference files
- bevy-upgrade: version migration workflow, transition references for 0.15→0.19, and 3 per-bump reference files
2026-07-07 17:52:10 +02:00

87 lines
3.7 KiB
Markdown

# 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::<T>()` 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::<AudioPlugin>()
.set(WindowPlugin { /* config */ })
.add_before::<RenderPlugin>(MyPlugin)
```
`.disable::<T>()`, `.enable::<T>()`, `.set(plugin)`, `.add_before::<Target>(p)`, `.add_after::<Target>(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::<R>()` | Insert via `Default`/`FromWorld` if absent |
| `add_systems(schedule, systems)` | Add to a schedule |
| `configure_sets(schedule, sets)` | Order system sets |
| `register_type::<T>()` | Reflection registry |
| `is_plugin_added::<T>()` | Plugin presence check |
| `register_required_components::<T, R>()` | Runtime component requirements |
## States
Three flavors:
- **FreelyMutableState** — changed via the `NextState<S>` resource.
- **SubStates** — exist only while the parent state is in a required variant.
- **ComputedStates** — derived: `fn compute(sources) -> Option<Self>`.
Registration: `app.init_state::<S>()` (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::<R>()`, `resource_added::<R>()`, `resource_changed::<R>()`, `resource_equals(val)`
- `any_with_component::<T>()`, `any_component_removed::<T>()`
- `on_message::<M>()` (renamed from `on_event`, 0.18)
- `run_once()`, `not(cond)`, `condition_changed(cond)`, `condition_changed_to(cond)`
Combine with `.and(cond)` / `.or(cond)`.