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

3.7 KiB

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:

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).