# Objective
- bevy_ecs has a expected lint that is both needed and unneeded
## Solution
- Change the logic so that it's always not needed
## Testing
`cargo clippy -p bevy_ecs --no-default-features --no-deps -- -D
warnings`
# Objective
- Many strings in bevy_ecs are created but only used for debug: system
name, component name, ...
- Those strings make a significant part of the final binary and are no
use in a released game
## Solution
- Use [`strings`](https://linux.die.net/man/1/strings) to find ...
strings in a binary
- Try to find where they come from
- Many are made from `type_name::<T>()` and only used in error / debug
messages
- Add a new structure `DebugName` that holds no value if `debug` feature
is disabled
- Replace `core::any::type_name::<T>()` by `DebugName::type_name::<T>()`
## Testing
Measurements were taken without the new feature being enabled by
default, to help with commands
### File Size
I tried building the `breakout` example with `cargo run --release
--example breakout`
|`debug` enabled|`debug` disabled|
|-|-|
|81621776 B|77735728B|
|77.84MB|74.13MB|
### Compilation time
`hyperfine --min-runs 15 --prepare "cargo clean && sleep 5"
'RUSTC_WRAPPER="" cargo build --release --example breakout'
'RUSTC_WRAPPER="" cargo build --release --example breakout --features
debug'`
```
breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug'
Benchmark 1: RUSTC_WRAPPER="" cargo build --release --example breakout
Time (mean ± σ): 84.856 s ± 3.565 s [User: 1093.817 s, System: 32.547 s]
Range (min … max): 78.038 s … 89.214 s 15 runs
Benchmark 2: RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
Time (mean ± σ): 92.303 s ± 2.466 s [User: 1193.443 s, System: 33.803 s]
Range (min … max): 90.619 s … 99.684 s 15 runs
Summary
RUSTC_WRAPPER="" cargo build --release --example breakout ran
1.09 ± 0.05 times faster than RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
```
Follow-up of #19274.
Make the `check_change_tick` methods, of which some are now public, take
`CheckChangeTicks` to make it obvious where this tick comes from, see
other PR.
This also affects the `System` trait, hence the many changed files.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
Remove `ArchetypeComponentId` and `archetype_component_access`.
Following #16885, they are no longer used by the engine, so we can stop
spending time calculating them or space storing them.
## Solution
Remove `ArchetypeComponentId` and everything that touches it.
The `System::update_archetype_component_access` method no longer needs
to update `archetype_component_access`. We do still need to update query
caches, but we no longer need to do so *before* running the system. We'd
have to touch every caller anyway if we gave the method a better name,
so just remove `System::update_archetype_component_access` and
`SystemParam::new_archetype` entirely, and update the query cache in
`Query::get_param`.
The `Single` and `Populated` params also need their query caches updated
in `SystemParam::validate_param`, so change `validate_param` to take
`&mut Self::State` instead of `&Self::State`.
# Objective
- `bevy_ecs` has lint errors without some features
## Solution
- Fix `clippy::allow-attributes-without-reason` when `bevy_reflect` is
disabled by adding a reason
- Fix `clippy::needless_return` when `std` is disabled by adding a gated
`expect` attribute and a comment to remove it when the `no_std` stuff is
addressed
## Testing
- `cargo clippy -p bevy_ecs --no-default-features --no-deps -- --D
warnings`
- CI
# Objective
Eliminate the need to write `cfg(feature = "track_location")` every time
one uses an API that may use location tracking. It's verbose, and a
little intimidating. And it requires code outside of `bevy_ecs` that
wants to use location tracking needs to either unconditionally enable
the feature, or include conditional compilation of its own. It would be
good for users to be able to log locations when they are available
without needing to add feature flags to their own crates.
Reduce the number of cases where code compiles with the `track_location`
feature enabled, but not with it disabled, or vice versa. It can be hard
to remember to test it both ways!
Remove the need to store a `None` in `HookContext` when the
`track_location` feature is disabled.
## Solution
Create an `MaybeLocation<T>` type that contains a `T` if the
`track_location` feature is enabled, and is a ZST if it is not. The
overall API is similar to `Option`, but whether the value is `Some` or
`None` is set at compile time and is the same for all values.
Default `T` to `&'static Location<'static>`, since that is the most
common case.
Remove all `cfg(feature = "track_location")` blocks outside of the
implementation of that type, and instead call methods on it.
When `track_location` is disabled, `MaybeLocation` is a ZST and all
methods are `#[inline]` and empty, so they should be entirely removed by
the compiler. But the code will still be visible to the compiler and
checked, so if it compiles with the feature disabled then it should also
compile with it enabled, and vice versa.
## Open Questions
Where should these types live? I put them in `change_detection` because
that's where the existing `MaybeLocation` types were, but we now use
these outside of change detection.
While I believe that the compiler should be able to remove all of these
calls, I have not actually tested anything. If we want to take this
approach, what testing is required to ensure it doesn't impact
performance?
## Migration Guide
Methods like `Ref::changed_by()` that return a `&'static
Location<'static>` will now be available even when the `track_location`
feature is disabled, but they will return a new `MaybeLocation` type.
`MaybeLocation` wraps a `&'static Location<'static>` when the feature is
enabled, and is a ZST when the feature is disabled.
Existing code that needs a `&Location` can call `into_option().unwrap()`
to recover it. Many trait impls are forwarded, so if you only need
`Display` then no changes will be necessary.
If that code was conditionally compiled, you may instead want to use the
methods on `MaybeLocation` to remove the need for conditional
compilation.
Code that constructs a `Ref`, `Mut`, `Res`, or `ResMut` will now need to
provide location information unconditionally. If you are creating them
from existing Bevy types, you can obtain a `MaybeLocation` from methods
like `Table::get_changed_by_slice_for()` or
`ComponentSparseSet::get_with_ticks`. Otherwise, you will need to store
a `MaybeLocation` next to your data and use methods like `as_ref()` or
`as_mut()` to obtain wrapped references.
# Objective
`bevy_ecs`'s `system` module is something of a grab bag, and *very*
large. This is particularly true for the `system_param` module, which is
more than 2k lines long!
While it could be defensible to put `Res` and `ResMut` there (lol no
they're in change_detection.rs, obviously), it doesn't make any sense to
put the `Resource` trait there. This is confusing to navigate (and
painful to work on and review).
## Solution
- Create a root level `bevy_ecs/resource.rs` module to mirror
`bevy_ecs/component.rs`
- move the `Resource` trait to that module
- move the `Resource` derive macro to that module as well (Rust really
likes when you pun on the names of the derive macro and trait and put
them in the same path)
- fix all of the imports
## Notes to reviewers
- We could probably move more stuff into here, but I wanted to keep this
PR as small as possible given the absurd level of import changes.
- This PR is ground work for my upcoming attempts to store resource data
on components (resources-as-entities). Splitting this code out will make
the work and review a bit easier, and is the sort of overdue refactor
that's good to do as part of more meaningful work.
## Testing
cargo build works!
## Migration Guide
`bevy_ecs::system::Resource` has been moved to
`bevy_ecs::resource::Resource`.
# Objective
- As stated in the related issue, this PR is to better align the feature
flag name with what it actually does and the plans for the future.
- Fixes#16852
## Solution
- Simple find / replace
## Testing
- Local run of `cargo run -p ci`
## Migration Guide
The `track_change_detection` feature flag has been renamed to
`track_location` to better reflect its extended capabilities.
# Objective
- Contributes to #15460
## Solution
- Added the following features:
- `std` (default)
- `async_executor` (default)
- `edge_executor`
- `critical-section`
- `portable-atomic`
- Gated `tracing` in `bevy_utils` to allow compilation on certain
platforms
- Switched from `tracing` to `log` for simple message logging within
`bevy_ecs`. Note that `tracing` supports capturing from `log` so this
should be an uncontroversial change.
- Fixed imports and added feature gates as required
- Made `bevy_tasks` optional within `bevy_ecs`. Turns out it's only
needed for parallel operations which are already gated behind
`multi_threaded` anyway.
## Testing
- Added to `compile-check-no-std` CI command
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section,portable-atomic --target
thumbv6m-none-eabi`
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section`
- `cargo check -p bevy_ecs --no-default-features`
## Draft Release Notes
Bevy's core ECS now supports `no_std` platforms.
In prior versions of Bevy, it was not possible to work with embedded or
niche platforms due to our reliance on the standard library, `std`. This
has blocked a number of novel use-cases for Bevy, such as an embedded
database for IoT devices, or for creating games on retro consoles.
With this release, `bevy_ecs` no longer requires `std`. To use Bevy on a
`no_std` platform, you must disable default features and enable the new
`edge_executor` and `critical-section` features. You may also need to
enable `portable-atomic` and `critical-section` if your platform does
not natively support all atomic types and operations used by Bevy.
```toml
[dependencies]
bevy_ecs = { version = "0.16", default-features = false, features = [
# Required for platforms with incomplete atomics (e.g., Raspberry Pi Pico)
"portable-atomic",
"critical-section",
# Optional
"bevy_reflect",
"serialize",
"bevy_debug_stepping",
"edge_executor"
] }
```
Currently, this has been tested on bare-metal x86 and the Raspberry Pi
Pico. If you have trouble using `bevy_ecs` on a particular platform,
please reach out either through a GitHub issue or in the `no_std`
working group on the Bevy Discord server.
Keep an eye out for future `no_std` updates as we continue to improve
the parity between `std` and `no_std`. We look forward to seeing what
kinds of applications are now possible with Bevy!
## Notes
- Creating PR in draft to ensure CI is passing before requesting
reviews.
- This implementation has no support for multithreading in `no_std`,
especially due to `NonSend` being unsound if allowed in multithreading.
The reason is we cannot check the `ThreadId` in `no_std`, so we have no
mechanism to at-runtime determine if access is sound.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Vic <59878206+Victoronz@users.noreply.github.com>
# Objective
- Fixes#6370
- Closes#6581
## Solution
- Added the following lints to the workspace:
- `std_instead_of_core`
- `std_instead_of_alloc`
- `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.
## Testing
- Ran CI locally
## Migration Guide
The MSRV is now 1.81. Please update to this version or higher.
## Notes
- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
Currently the resource doesn't get dropped if thread panics. This is
presumably to prevent !SEND resource from being dropped by wrong thread.
But, this logic is not needed for SEND resources. So we don't need this
check for SEND resource.
Fixes#15144
## Solution
We check if resource is !SEND before, validating that correct thread is
dropping the resource.
## Testing
- Did you test these changes? If so, how?
I did run cargo test on bevy.
- Are there any parts that need more testing?
No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Nothing special
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
x86_64 desktop
# Objective
Fixes#14782
## Solution
Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?
Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.
## Testing
`cargo clippy` and `cargo run -p ci` are happy.
# Objective
- Make it possible to know *what* changed your component or resource.
- Common need when debugging, when you want to know the last code
location that mutated a value in the ECS.
- This feature would be very useful for the editor alongside system
stepping.
## Solution
- Adds the caller location to column data.
- Mutations now `track_caller` all the way up to the public API.
- Commands that invoke these functions immediately call
`Location::caller`, and pass this into the functions, instead of the
functions themselves attempting to get the caller. This would not work
for commands which are deferred, as the commands are executed by the
scheduler, not the user's code.
## Testing
- The `component_change_detection` example now shows where the component
was mutated:
```
2024-07-28T06:57:48.946022Z INFO component_change_detection: Entity { index: 1, generation: 1 }: New value: MyComponent(0.0)
2024-07-28T06:57:49.004371Z INFO component_change_detection: Entity { index: 1, generation: 1 }: New value: MyComponent(1.0)
2024-07-28T06:57:49.012738Z WARN component_change_detection: Change detected!
-> value: Ref(MyComponent(1.0))
-> added: false
-> changed: true
-> changed by: examples/ecs/component_change_detection.rs:36:23
```
- It's also possible to inspect change location from a debugger:
<img width="608" alt="image"
src="https://github.com/user-attachments/assets/c90ecc7a-0462-457a-80ae-42e7f5d346b4">
---
## Changelog
- Added source locations to ECS change detection behind the
`track_change_detection` flag.
## Migration Guide
- Added `changed_by` field to many internal ECS functions used with
change detection when the `track_change_detection` feature flag is
enabled. Use Location::caller() to provide the source of the function
call.
---------
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- Part of #11590
- Fix `unsafe_op_in_unsafe_fn` for trivial cases in bevy_ecs
## Solution
Fix `unsafe_op_in_unsafe_fn` in bevy_ecs for trivial cases, i.e., add an
`unsafe` block when the safety comment already exists or add a comment
like "The invariants are uphold by the caller".
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
`Column` unconditionally requires three separate allocations: one for
the data, and two for the tick Vecs. The tick Vecs aren't really needed
for Resources, so we're allocating a bunch of one-element Vecs, and it
costs two extra dereferences when fetching/inserting/removing resources.
## Solution
Drop one level lower in `ResourceData` and directly store a `BlobVec`
and two `UnsafeCell<Tick>`s. This should significantly shrink
`ResourceData` (exchanging 6 usizes for 2 u32s), removes the need to
dereference two separate ticks when inserting/removing/fetching
resources, and can significantly decrease the number of small
allocations the ECS makes by default.
This tentatively might have a non-insignificant impact on the CPU cost
for rendering since we're constantly fetching resources in draw
functions, depending on how aggressively inlined the functions are.
This requires reimplementing some of the unsafe functions that `Column`
wraps, but it also allows us to delete a few Column APIs that were only
used for Resources, so the total amount of unsafe we're maintaining
shouldn't change significantly.
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
# Objective
- Fixes#10806
## Solution
Replaced `new` and `index` methods for both `TableRow` and `TableId`
with `from_*` and `as_*` methods. These remove the need to perform
casting at call sites, reducing the total number of casts in the Bevy
codebase. Within these methods, an appropriate `debug_assertion` ensures
the cast will behave in an expected manner (no wrapping, etc.). I am
using a `debug_assertion` instead of an `assert` to reduce any possible
runtime overhead, however minimal. This choice is something I am open to
changing (or leaving up to another PR) if anyone has any strong
arguments for it.
---
## Changelog
- `ComponentSparseSet::sparse` stores a `TableRow` instead of a `u32`
(private change)
- Replaced `TableRow::new` and `TableRow::index` methods with
`TableRow::from_*` and `TableRow::as_*`, with `debug_assertions`
protecting any internal casting.
- Replaced `TableId::new` and `TableId::index` methods with
`TableId::from_*` and `TableId::as_*`, with `debug_assertions`
protecting any internal casting.
- All `TableId` methods are now `const`
## Migration Guide
- `TableRow::new` -> `TableRow::from_usize`
- `TableRow::index` -> `TableRow::as_usize`
- `TableId::new` -> `TableId::from_usize`
- `TableId::index` -> `TableId::as_usize`
---
## Notes
I have chosen to remove the `index` and `new` methods for the following
chain of reasoning:
- Across the codebase, `new` was called with a mixture of `u32` and
`usize` values. Likewise for `index`.
- Choosing `new` to either be `usize` or `u32` would break half of these
call-sites, requiring `as` casting at the site.
- Adding a second method `new_u32` or `new_usize` avoids the above, bu
looks visually inconsistent.
- Therefore, they should be replaced with `from_*` and `as_*` methods
instead.
Worth noting is that by updating `ComponentSparseSet`, there are now
zero instances of interacting with the inner value of `TableRow` as a
`u32`, it is exclusively used as a `usize` value (due to interactions
with methods like `len` and slice indexing). I have left the `as_u32`
and `from_u32` methods as the "proper" constructors/getters.
# Objective
- The tick access methods mention "ticks" (as in: plural). Yet, most of
them only access a single tick.
## Solution
- Rename those methods and fix docs to reflect the singular aspect of
the return values
---
## Migration Guide
The following method names were renamed, from `foo_ticks_bar` to
`foo_tick_bar` (`ticks` is now singular, `tick`):
- `ComponentSparseSet::get_added_ticks` → `get_added_tick`
- `ComponentSparseSet::get_changed_ticks` → `get_changed_tick`
- `Column::get_added_ticks` → `get_added_tick`
- `Column::get_changed_ticks` → `get_changed_tick`
- `Column::get_added_ticks_unchecked` → `get_added_tick_unchecked`
- `Column::get_changed_ticks_unchecked` → `get_changed_tick_unchecked`
# Objective
- Fixes unclear warning when `insert_non_send_resource` is called on a
Send resource
## Solution
- Add a message to the asssert statement that checks this
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
- Fixes#3158
## Solution
- clear columns
My implementation of `clear_resources` do not remove the components itself but it clears the columns that keeps the resource data. I'm not sure if the issue meant to clear all resources, even the components and component ids (which I'm not sure if it's possible)
Co-authored-by: 2ne1ugly <47616772+2ne1ugly@users.noreply.github.com>
# Objective
* `World::init_resource` and `World::get_resource_or_insert_with` are implemented naively, and as such they perform duplicate `TypeId -> ComponentId` lookups.
* `World::get_resource_or_insert_with` contains an additional duplicate `ComponentId -> ResourceData` lookup.
* This function also contains an unnecessary panic branch, which we rely on the optimizer to be able to remove.
## Solution
Implement the functions using engine-internal code, instead of combining high-level functions. This allows computed variables to persist across different branches, instead of being recomputed.
# Objective
Fixes#3310. Fixes#6282. Fixes#6278. Fixes#3666.
## Solution
Split out `!Send` resources into `NonSendResources`. Add a `origin_thread_id` to all `!Send` Resources, check it on dropping `NonSendResourceData`, if there's a mismatch, panic. Moved all of the checks that `MainThreadValidator` would do into `NonSendResources` instead.
All `!Send` resources now individually track which thread they were inserted from. This is validated against for every access, mutation, and drop that could be done against the value.
A regression test using an altered version of the example from #3310 has been added.
This is a stopgap solution for the current status quo. A full solution may involve fully removing `!Send` resources/components from `World`, which will likely require a much more thorough design on how to handle the existing in-engine and ecosystem use cases.
This PR also introduces another breaking change:
```rust
use bevy_ecs::prelude::*;
#[derive(Resource)]
struct Resource(u32);
fn main() {
let mut world = World::new();
world.insert_resource(Resource(1));
world.insert_non_send_resource(Resource(2));
let res = world.get_resource_mut::<Resource>().unwrap();
assert_eq!(res.0, 2);
}
```
This code will run correctly on 0.9.1 but not with this PR, since NonSend resources and normal resources have become actual distinct concepts storage wise.
## Changelog
Changed: Fix soundness bug with `World: Send`. Dropping a `World` that contains a `!Send` resource on the wrong thread will now panic.
## Migration Guide
Normal resources and `NonSend` resources no longer share the same backing storage. If `R: Resource`, then `NonSend<R>` and `Res<R>` will return different instances from each other. If you are using both `Res<T>` and `NonSend<T>` (or their mutable variants), to fetch the same resources, it's strongly advised to use `Res<T>`.
# Objective
Prevent future unsoundness that was seen in #6623.
## Solution
Newtype both indexes in `Archetype` and `Table` as `ArchetypeRow` and `TableRow`. This avoids weird numerical manipulation on the indices, and can be stored and treated opaquely. Also enforces the source and destination of where these indices at a type level.
---
## Changelog
Changed: `Archetype` indices and `Table` rows have been newtyped as `ArchetypeRow` and `TableRow`.
# Objective
Fixes#4884. `ComponentTicks` stores both added and changed ticks contiguously in the same 8 bytes. This is convenient when passing around both together, but causes half the bytes fetched from memory for the purposes of change detection to effectively go unused. This is inefficient when most queries (no filter, mutating *something*) only write out to the changed ticks.
## Solution
Split the storage for change detection ticks into two separate `Vec`s inside `Column`. Fetch only what is needed during iteration.
This also potentially also removes one blocker from autovectorization of dense queries.
EDIT: This is confirmed to enable autovectorization of dense queries in `for_each` and `par_for_each` where possible. Unfortunately `iter` has other blockers that prevent it.
### TODO
- [x] Microbenchmark
- [x] Check if this allows query iteration to autovectorize simple loops.
- [x] Clean up all of the spurious tuples now littered throughout the API
### Open Questions
- ~~Is `Mut::is_added` absolutely necessary? Can we not just use `Added` or `ChangeTrackers`?~~ It's optimized out if unused.
- ~~Does the fetch of the added ticks get optimized out if not used?~~ Yes it is.
---
## Changelog
Added: `Tick`, a wrapper around a single change detection tick.
Added: `Column::get_added_ticks`
Added: `Column::get_column_ticks`
Added: `SparseSet::get_added_ticks`
Added: `SparseSet::get_column_ticks`
Changed: `Column` now stores added and changed ticks separately internally.
Changed: Most APIs returning `&UnsafeCell<ComponentTicks>` now returns `TickCells` instead, which contains two separate `&UnsafeCell<Tick>` for either component ticks.
Changed: `Query::for_each(_mut)`, `Query::par_for_each(_mut)` will now leverage autovectorization to speed up query iteration where possible.
## Migration Guide
TODO
# Objective
In bevy 0.8 you could list all resources using `world.archetypes().resource().components()`. As far as I can tell the resource archetype has been replaced with the `Resources` storage, and it would be nice if it could be used to iterate over all resource component IDs as well.
## Solution
- add `fn Resources::iter(&self) -> impl Iterator<Item = (ComponentId, &ResourceData)>`
# Objective
At least partially addresses #6282.
Resources are currently stored as a dedicated Resource archetype (ID 1). This allows for easy code reusability, but unnecessarily adds 72 bytes (on 64-bit systems) to the struct that is only used for that one archetype. It also requires several fields to be `pub(crate)` which isn't ideal.
This should also remove one sparse-set lookup from fetching, inserting, and removing resources from a `World`.
## Solution
- Add `Resources` parallel to `Tables` and `SparseSets` and extract the functionality used by `Archetype` in it.
- Remove `unique_components` from `Archetype`
- Remove the `pub(crate)` on `Archetype::components`.
- Remove `ArchetypeId::RESOURCE`
- Remove `Archetypes::resource` and `Archetypes::resource_mut`
---
## Changelog
Added: `Resources` type to store resources.
Added: `Storages::resource`
Removed: `ArchetypeId::RESOURCE`
Removed: `Archetypes::resource` and `Archetypes::resources`
Removed: `Archetype::unique_components` and `Archetypes::unique_components_mut`
## Migration Guide
Resources have been moved to `Resources` under `Storages` in `World`. All code dependent on `Archetype::unique_components(_mut)` should access it via `world.storages().resources()` instead.
All APIs accessing the raw data of individual resources (mutable *and* read-only) have been removed as these APIs allowed for unsound unsafe code. All usages of these APIs should be changed to use `World::{get, insert, remove}_resource`.