✨ Scaffold bevy plugin with bevy-0.19 and bevy-upgrade skills
Add plugin skeleton with versioned skill directories, TODO SKILL.md scaffolds with goals for skill-creator, and copy over bevy-skill-research reports from spacecraft into docs/workpad/research/.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Bevy Skill Research: ECS Core
|
||||
|
||||
> **Bevy version**: 0.18, with 0.19 notes
|
||||
> **Date**: 2026-07-07
|
||||
|
||||
## Components
|
||||
|
||||
**Derive**: `#[derive(Component)]` on structs/enums. Requires `Send + Sync + 'static`.
|
||||
|
||||
**Storage**:
|
||||
- Table (default) — fast iteration
|
||||
- `#[component(storage = "SparseSet")]` — fast insert/remove
|
||||
|
||||
**Immutable components** (0.18+): `#[component(immutable)]` — restricts to `&T` only, no `&mut T`.
|
||||
|
||||
**Required components**: `#[require(B, C)]` — auto-inserts `B` and `C` when this component is added. Supports constructors: `B(value)`, `C { field: val }`, function calls, `= expr`.
|
||||
|
||||
**Hooks**: `on_add`, `on_insert`, `on_replace`, `on_remove`, `on_despawn` — set via `#[component(on_add = fn_name)]` or self-referential `#[component(on_add)]`.
|
||||
|
||||
**Clone behavior**: `#[component(clone_behavior = Ignore)]` to skip during entity clone.
|
||||
|
||||
**Bundles removed** (0.16+): Use `#[require(...)]` or spawn with tuples instead of `#[derive(Bundle)]`.
|
||||
|
||||
## Resources
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `Res<T>` | Shared read access |
|
||||
| `ResMut<T>` | Exclusive write access |
|
||||
| `Option<Res<T>>` / `Option<ResMut<T>>` | Resources that may not exist |
|
||||
| `Local<'a, T>` | Per-system private state, persists across calls, default-initialized |
|
||||
| `NonSend<T>` / `NonSendMut<T>` | For `!Send` resources |
|
||||
|
||||
World methods: `init_resource::<R>()` (uses `Default`), `insert_resource(value)`, `remove_resource::<R>()`.
|
||||
|
||||
**0.19 change**: Resources implement `Component` and live on abstract entities. `Query<Entity>` now matches resource entities — filter with `Without<IsResource>`. Cannot derive both `Component` and `Resource` on one type.
|
||||
|
||||
## Systems
|
||||
|
||||
**Standard**: any `fn(params...) { }` where each param implements `SystemParam`.
|
||||
|
||||
**Fallible** (0.18+): `fn system(params...) -> Result` — bare `Result` (alias for `Result<(), BevyError>`). Errors are logged, system continues on next tick. `?` operator works with any error convertible to `BevyError`.
|
||||
|
||||
**Exclusive**: `fn system(world: &mut World) { }` — full world access, blocks parallelism.
|
||||
|
||||
**Registration**: `app.add_systems(Update, (sys_a, sys_b))` or `app.add_systems(Startup, setup)`.
|
||||
|
||||
### Valid SystemParam Types
|
||||
|
||||
`Query`, `Res`, `ResMut`, `Commands`, `Local`, `MessageReader`, `MessageWriter`, `ParamSet`, `Single`, `Populated`, `SystemName`, `SystemChangeTick`, `RemovedComponents<T>`, `DeferredWorld`, `&World`, `()`, `Option<T>`, `Result<T, SystemParamValidationError>`, `PhantomData<T>`.
|
||||
|
||||
## Queries
|
||||
|
||||
**Signature**: `Query<D, F>` where `D: QueryData`, `F: QueryFilter` (default `()`).
|
||||
|
||||
### Data Parameters
|
||||
- `&T` — read
|
||||
- `&mut T` — write
|
||||
- `Entity` — entity ID
|
||||
- `Has<T>` — returns bool
|
||||
- Tuples of the above
|
||||
|
||||
### Filters
|
||||
| Filter | Fires when |
|
||||
|--------|-----------|
|
||||
| `With<T>` | Entity has component T |
|
||||
| `Without<T>` | Entity lacks component T |
|
||||
| `Added<T>` | First tick after component added |
|
||||
| `Changed<T>` | First tick after add or mut deref |
|
||||
| `Spawned` | First tick after entity spawn (new) |
|
||||
| `Or<(A, B)>` | Either filter matches |
|
||||
|
||||
### Key Methods
|
||||
- `.iter()` / `.iter_mut()` — iterate all matching
|
||||
- `.get(entity)` / `.get_mut(entity)` — single entity lookup
|
||||
- `.single()` — panics if not exactly one match
|
||||
- `.par_iter()` / `.par_iter_mut()` — parallel iteration
|
||||
|
||||
### Specialized System Params
|
||||
- `Single<D, F>` — system param alternative to `query.single()`, panics if not exactly one
|
||||
- `Populated<D, F>` — system skips execution if query is empty
|
||||
|
||||
### Custom Derives
|
||||
- `#[derive(QueryData)]` — for complex query data
|
||||
- `#[derive(QueryFilter)]` — for reusable filter combinations
|
||||
|
||||
## Commands
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `commands.spawn((CompA, CompB))` | Spawn entity with tuple, returns `EntityCommands` |
|
||||
| `commands.spawn_empty()` | Empty entity, chain `.insert(bundle)` |
|
||||
| `commands.spawn_batch(iter)` | Batch spawn from iterator |
|
||||
| `commands.entity(e).insert(comp)` | Add component to existing entity |
|
||||
| `commands.entity(e).insert_if_new(comp)` | Add only if absent |
|
||||
| `commands.entity(e).remove::<T>()` | Remove component |
|
||||
| `commands.entity(e).despawn()` | Destroy entity (auto-recursive with children) |
|
||||
| `commands.queue(custom_command)` | Push custom `Command` impl |
|
||||
|
||||
## System Ordering
|
||||
|
||||
- `(a, b).chain()` — `a` runs before `b`
|
||||
- `.before(system_or_set)` / `.after(system_or_set)` — explicit ordering
|
||||
- `#[derive(SystemSet)]` — define named sets for grouping
|
||||
- `app.configure_sets(Update, SetA.before(SetB))` — order sets
|
||||
- `AmbiguousSystemConflictsWarning` warns about unordered systems with overlapping access
|
||||
Reference in New Issue
Block a user