docs: update skill guides for auto-tracking and batching changes

This commit is contained in:
2026-07-21 11:03:01 +08:00
parent 4b94f411bf
commit 52e1e8fdc9
2 changed files with 55 additions and 31 deletions
+17 -13
View File
@@ -38,8 +38,8 @@ Key ADRs to keep in mind when changing the library:
| 002 | 32-bit Entity (24 ID + 8 version) | Fits in register, enough headroom |
| 003 | Explicit query iteration | Visible cost model, no code-gen needed |
| 004 | Registration order for systems | Simplest model that works at this scale |
| 005 | Manual `MarkModified` for value changes | No per-component overhead |
| 006 | Deferred change posting | Prevents mid-system reentrancy |
| 005 | Auto-tracking in batching scopes | Eliminates manual `MarkModified` in systems |
| 006 | Deferred mutation batching | Prevents mid-system reentrancy, safe iteration |
| 007 | R3 for reactivity | Zero-allocation, UI lifecycle-friendly |
| 008 | Commands as serializable structs in a queue | Not ECS state |
| 009 | Singleton per component type | Each singleton gets its own entity |
@@ -73,12 +73,12 @@ Uses swap-remove for O(1) deletion.
Zero-allocation `ref struct` enumerators returned by `world.Select<T1..T6>()`.
Drive from the smallest sparse set to minimize probes. Support `foreach` via
`GetEnumerator()` returning `this`. Expose `Entity` and `ref Item1`..`ref ItemN`
properties. Constructor/dispose manage `BeginIteration()`/`EndIteration()` for
pending mutation flushing. Singleton entities are excluded via
`IsSingletonEntity()` check.
`GetEnumerator()` returning `this`. Expose `Entity`, `Ref1`..`RefN` (mutable,
tracked for auto-dirty-marking), and `Val1`..`ValN` (read-only, untracked).
Constructor/dispose manage `BeginBatching()`/`EndBatching()` for pending
mutation flushing. Singleton entities are excluded via `IsSingletonEntity()`.
Also provides `FindEntity<T>()` (first match) and `FindEntities<T>()` (all matches).
Also provides `FindEntity<T>()` (first match).
### `Query<T1..T6>` — generic query descriptors
@@ -90,8 +90,11 @@ method adds exclusion filters without changing the arity. Replaces the old
Manages an ordered list of `ISystem`. `RunAll()`:
1. Drain commands (pre-tick).
2. For each system: run it → drain commands → post changes.
3. Drain commands + post changes (post-tick).
2. `BeginBatching()` — outer batching scope for the tick.
3. For each system: run via `Run` extension (nested batch) → drain commands →
flush pending mutations → post changes.
4. `EndBatching()` — auto-marks + flushes remaining.
5. Drain commands + post changes (post-tick).
### `WorldSerializer` — save/load
@@ -189,11 +192,12 @@ when there are no fields to compare.
## Common Pitfalls
- **Forgetting `MarkModified` after mutating a `ref` component.** Changes won't
propagate to R3 subscribers. Debug builds have a warning for this.
- **Using `ValN` when you meant to mutate.** `ValN` returns a `ref readonly`
writes through it still work but won't be tracked for auto-dirty-marking.
Use `RefN` for any component you intend to mutate.
- **Modifying components during iteration.** Pending mutations are flushed at
the end of iteration (via `BeginIteration`/`EndIteration`). Adding/removing
components mid-iteration is safe — they're deferred.
the end of the batching scope. Adding/removing components mid-iteration is
safe — they're deferred.
- **Type not public or missing `[MessagePackObject]`.** Serialization will fail.
The `MessagePackAnalyzer` catches most issues at compile time.
- **Singletons each have their own entity allocated automatically by