diff --git a/docs/tutorials/src/12_tracked.md b/docs/tutorials/src/12_tracked.md index 73cd97e30..a9d0a2df9 100644 --- a/docs/tutorials/src/12_tracked.md +++ b/docs/tutorials/src/12_tracked.md @@ -8,12 +8,12 @@ To avoid a lot of unnecessary computation when updating components it would be nice if we could somehow check for only those entities that are updated and recalculate only those. -We might also need to keep an external resource in sync with changes -to components in Specs `World`, and we only want to propagate actual changes, not +We might also need to keep an external resource in sync with changes to +components in Specs `World`, and we only want to propagate actual changes, not do a full sync every frame. -This is where `FlaggedStorage` comes into play. By wrapping a component's -actual storage in a `FlaggedStorage`, we can subscribe to modification events, and +This is where `FlaggedStorage` comes into play. By wrapping a component's actual +storage in a `FlaggedStorage`, we can subscribe to modification events, and easily populate bitsets with only the entities that have actually changed. Let's look at some code: @@ -66,29 +66,75 @@ impl<'a> System<'a> for Sys { fn setup(&mut self, res: &mut Resources) { Self::SystemData::setup(res); - self.reader_id = Some(WriteStorage::::fetch(&res).register_reader()); + self.reader_id = Some( + WriteStorage::::fetch(&res).register_reader() + ); } } ``` There are three different event types that we can receive: -* `ComponentEvent::Inserted` - will be sent when a component is added to the +- `ComponentEvent::Inserted` - will be sent when a component is added to the storage -* `ComponentEvent::Modified` - will be sent when a component is fetched mutably +- `ComponentEvent::Modified` - will be sent when a component is fetched mutably from the storage -* `ComponentEvent::Removed` - will be sent when a component is removed from the +- `ComponentEvent::Removed` - will be sent when a component is removed from the storage -Note that because of how `ComponentEvent` works, if you iterate mutably over a +## Gotcha: Iterating `FlaggedStorage` Mutably + +Because of how `ComponentEvent` works, if you iterate mutably over a component storage using `Join`, all entities that are fetched by the `Join` will be flagged as modified even if nothing was updated in them. +For example, this will cause all `comps` components to be flagged as modified: + +```rust,ignore +// **Never do this** if `comps` uses `FlaggedStorage`. +// +// This will flag all components as modified regardless of whether the inner +// loop actually modified the component. +for comp in (&mut comps).join() { + // ... +} +``` + +Instead, you will want to either: + +- Restrict the components mutably iterated over, for example by joining with a + `BitSet` or another component storage. +- Iterating over the components use a `RestrictedStorage` and only fetch the + component as mutable if/when needed. + +## `RestrictedStorage` + +If you need to iterate over a `FlaggedStorage` mutably and don't want every +component to be marked as modified, you can use a `RestrictedStorage` and only +fetch the component as mutable if/when needed. + +```rust,ignore +for (entity, mut comp) in (&entities, &mut comps.restrict_mut()).join() { + // Check whether this component should be modified, without fetching it as + // mutable. + if comp.get_unchecked().condition < 5 { + let mut comp = comp.get_mut_unchecked(); + // ... + } +} +``` + ## Start and Stop event emission -Sometimes you may want to perform some operations on the storage, but you don't want -that these operations produce any event. +Sometimes you may want to perform some operations on the storage, but you don't +want that these operations produce any event. + +You can use the function `storage.set_event_emission(false)` to suppress the +event writing for of any action. When you want to re activate them you can +simply call `storage.set_event_emission(true)`. + +--- -You can use the function `storage.set_event_emission(false)` to suppress the event writing for -of any action. When you want to re activate them you can simply call -`storage.set_event_emission(true)`. \ No newline at end of file +_See +[FlaggedStorage Doc](https://docs.rs/specs/latest/specs/struct.FlaggedStorage.html) +for more into._ \ No newline at end of file