Commit graph

426 commits

Author SHA1 Message Date
Ame
9d67edc3a6
fix some typos (#12038)
# Objective

Split - containing only the fixed typos

-
https://github.com/bevyengine/bevy/pull/12036#pullrequestreview-1894738751


# Migration Guide
In `crates/bevy_mikktspace/src/generated.rs` 

```rs
// before
pub struct SGroup {
    pub iVertexRepresentitive: i32,
    ..
}

// after
pub struct SGroup {
    pub iVertexRepresentative: i32,
    ..
}
```

In `crates/bevy_core_pipeline/src/core_2d/mod.rs`

```rs
// before
Node2D::ConstrastAdaptiveSharpening

// after
Node2D::ContrastAdaptiveSharpening
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: François <mockersf@gmail.com>
2024-02-22 18:55:22 +00:00
Yutao Yuan
11a3b77811
Create imported_assets directory with full path (#12022)
# Objective

- The file asset source currently creates the `imported_assets/Default`
directory with relative path, which leads to wrongly created directories
when the executable is run with a working directory different from the
project root.

## Solution

- Use the full path instead.
2024-02-21 21:59:59 +00:00
Nicola Papale
7e782f1edf
Fix example docs on embedded_asset macro (#12003)
# Objective

The derive macro wasn't doc-commented, so it showed up in the generated
doc as follow:

```rust
#[derive(Asset, TypePath)]
let shader = asset_server.load::<Shader>("embedded://bevy_rock/render/rock.wgsl");
```

Which is very confusing

## Solution

Comment the `derive` attribute as well
2024-02-20 16:13:30 +00:00
Noa
cb5ff51d1e
Qualify embedded_asset expansion with $crate:: (#11961)
# Objective

Right now, if you call `embedded_asset` with 2 arguments as a qualified
path it doesn't work (`bevy::asset::embedded_asset!(app, "foo.wgsl")` ->
"cannot find macro `embedded_asset` in this scope")

## Solution

Use `$crate::` in expansion for 2-arg case.
2024-02-18 21:52:32 +00:00
thepackett
16d710cb3f
Fix asset loader registration warning (#11870)
# Objective

When registering and preregistering asset loaders, there would be a
`warn!` if multiple asset loaders use a given extension, and an `info!`
if multiple asset loaders load the same asset type. Since both of these
situations are individually fine, it was decided that these messages
should be removed.

## Solution

Replace both of these messages with a new `warn!` that notes that if
multiple asset loaders share the same asset type _and_ share extensions,
that the loader must be specified in the `.meta` file for those assets
in order to solve the ambiguity. This is a more useful message, since it
notes when a user must take special action / consideration.
2024-02-16 16:30:10 +00:00
Zachary Harrold
7b5a4ec4ed
Use Asset Path Extension for AssetLoader Disambiguation (#11644)
# Objective

- Fixes #11638
- See
[here](https://github.com/bevyengine/bevy/issues/11638#issuecomment-1920508465)
for details on the cause of this issue.

## Solution

- Modified `AssetLoaders` to capture possibility of multiple
`AssetLoader` registrations operating on the same `Asset` type, but
different extensions.
- Added an algorithm which will attempt to resolve via `AssetLoader`
name, then `Asset` type, then by extension. If at any point multiple
loaders fit a particular criteria, the next criteria is used as a tie
breaker.
2024-02-12 15:44:55 +00:00
James Liu
eee71bfa93
Put asset_events behind a run condition (#11800)
# Objective
Scheduling low cost systems has significant overhead due to task pool
contention and the extra machinery to schedule and run them. Following
the example of #7728, `asset_events` is good example of this kind of
system, where there is no work to be done when there are no queued asset
events.

## Solution
Put a run condition on it that checks if there are any queued events.

## Performance
Tested against `many_foxes`, we can see a slight improvement in the
total time spent in `UpdateAssets`. Also noted much less volatility due
to not being at the whim of the OS thread scheduler.

![image](https://github.com/bevyengine/bevy/assets/3137680/e0b282bf-27d0-4fe4-81b9-ecd72ab258e5)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-12 15:19:36 +00:00
Doonv
054134fba2
Add ReflectKind (#11664)
# Objective

Fix https://github.com/bevyengine/bevy/issues/11657

## Solution

Add a `ReflectKind` enum, add `Reflect::reflect_kind` which returns a
`ReflectKind`, and add `kind` method implementions to `ReflectRef`,
`ReflectMut`, and `ReflectOwned`, which returns a `ReflectKind`.

I also changed `AccessError` to use this new struct instead of it's own
`TypeKind` struct.

---

## Changelog

- Added `ReflectKind`, an enumeration over the kinds of a reflected type
without its data.
- Added `Reflect::reflect_kind` (with default implementation)
- Added implementation for the `kind` method on `ReflectRef`,
`ReflectMut`, and `ReflectOwned` which gives their kind without any
information, as a `ReflectKind`
2024-02-07 00:36:23 +00:00
SpecificProtagonist
21aa5fe2b6
Use TypeIdMap whenever possible (#11684)
Use `TypeIdMap<T>` instead of `HashMap<TypeId, T>`

- ~~`TypeIdMap` was in `bevy_ecs`. I've kept it there because of
#11478~~
- ~~I haven't swapped `bevy_reflect` over because it doesn't depend on
`bevy_ecs`, but I'd also be happy with moving `TypeIdMap` to
`bevy_utils` and then adding a dependency to that~~
- ~~this is a slight change in the public API of
`DrawFunctionsInternal`, does this need to go in the changelog?~~

## Changelog
- moved `TypeIdMap` to `bevy_utils`
- changed `DrawFunctionsInternal::indices` to `TypeIdMap`

## Migration Guide

- `TypeIdMap` now lives in `bevy_utils`
- `DrawFunctionsInternal::indices` now uses a `TypeIdMap`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-03 23:47:04 +00:00
Tristan Guichaoua
694c06f3d0
Inverse missing_docs logic (#11676)
# Objective

Currently the `missing_docs` lint is allowed-by-default and enabled at
crate level when their documentations is complete (see #3492).
This PR proposes to inverse this logic by making `missing_docs`
warn-by-default and mark crates with imcomplete docs allowed.

## Solution

Makes `missing_docs` warn at workspace level and allowed at crate level
when the docs is imcomplete.
2024-02-03 21:40:55 +00:00
CowSociety
8866c61161
Fix AssetTransformer breaking LabeledAssets (#11626)
# Objective

- `AssetTransformer` provides an input asset, and output an asset, but
provides no access to the `LabeledAsset`'s created by the `AssetLoader`.
Labeled sub assets are an extremely important piece of many assets, Gltf
in particular, and without them the amount of transformation on an asset
is limited. In order for `AssetTransformer`'s to be useful, they need to
have access to these sub assets.
- LabeledAsset's loaded by `AssetLoader`s are provided to `AssetSaver`s
in the `LoadAndSave` process, but the `LoadTransformAndSave` process
drops these values in the transform stage, and so `AssetSaver` is given
none.
- Fixes #11606

Ideally the AssetTransformer should not ignore labeled sub assets, and
they should be kept at least for the AssetSaver

## Solution

- I created a new struct similar to `SavedAsset` named
`TransformedAsset` which holds the input asset, and the HashMap of
`LabeledAsset`s. The transform function now takes as input a
`TransformedAsset`, and returns a `TransformedAsset::<AssetOutput>`.
This gives the transform function access to the labeled sub assets
created by the `AssetLoader`.
- I also created `TransformedSubAsset` which holds mutable references to
a sub asset and that sub assets HashMap of `LabeledAsset`s. This allows
you to travers the Tree of `LabeledAsset`s by reference relatively
easily.
- The `LoadTransformAndSave` processor was then reworked to use the new
structs, stopping the `LabeledAsset`s from being dropped.

---

## Changelog

- Created TransformedAsset struct and TransformedSubAsset struct.
- Changed `get_untyped_handle` to return a `UntypedHandle` directly
rather than a reference and added `get_handle` as a typed variant in
SavedAsset and TransformedAsset
- Added `SavedAsset::from_transformed` as a constructor from a
`TransformedAsset`
- Switched LoadTransformAndSave process code to work with new
`TransformedAsset` type
- Added a `ProcessError` for `AssetTransformer` in process.rs
- Switched `AssetTransformer::transform` to use `TransformedAsset` as
input and output.
- Switched `AssetTransformer` to use a `BoxedFuture` like `AssetLoader`
and `AssetSaver` to allow for async transformation code.
- Updated AssetTransformer example to use new structure.
2024-02-02 14:57:31 +00:00
Duncan
176223b406
Fix embedded asset path manipulation (#10383)
# Objective

Fixes #10377

## Solution

Use `Path::strip_prefix` instead of `str::split`. Avoid any explicit "/"
characters in path manipulation.

---

## Changelog

- Added: example of embedded asset loading
- Added: support embedded assets in external crates
- Fixed: resolution of embedded assets
- Fixed: unexpected runtime panic during asset path resolution

## Migration Guide

No API changes.

---------

Co-authored-by: Shane Celis <shane.celis@gmail.com>
2024-02-02 14:49:05 +00:00
Zachary Harrold
afa7b5cba5
Added Support for Extension-less Assets (#10153)
# Objective

- Addresses **Support processing and loading files without extensions**
from #9714
- Addresses **More runtime loading configuration** from #9714
- Fixes #367
- Fixes #10703

## Solution

`AssetServer::load::<A>` and `AssetServer::load_with_settings::<A>` can
now use the `Asset` type parameter `A` to select a registered
`AssetLoader` without inspecting the provided `AssetPath`. This change
cascades onto `LoadContext::load` and `LoadContext::load_with_settings`.
This allows the loading of assets which have incorrect or ambiguous file
extensions.

```rust
// Allow the type to be inferred by context
let handle = asset_server.load("data/asset_no_extension");

// Hint the type through the handle
let handle: Handle<CustomAsset> = asset_server.load("data/asset_no_extension");

// Explicit through turbofish
let handle = asset_server.load::<CustomAsset>("data/asset_no_extension");
```

Since a single `AssetPath` no longer maps 1:1 with an `Asset`, I've also
modified how assets are loaded to permit multiple asset types to be
loaded from a single path. This allows for two different `AssetLoaders`
(which return different types of assets) to both load a single path (if
requested).

```rust
// Uses GltfLoader
let model = asset_server.load::<Gltf>("cube.gltf");

// Hypothetical Blob loader for data transmission (for example)
let blob = asset_server.load::<Blob>("cube.gltf");
```

As these changes are reflected in the `LoadContext` as well as the
`AssetServer`, custom `AssetLoaders` can also take advantage of this
behaviour to create more complex assets.

---

## Change Log

- Updated `custom_asset` example to demonstrate extension-less assets.
- Added `AssetServer::get_handles_untyped` and Added
`AssetServer::get_path_ids`

## Notes

As a part of that refactor, I chose to store `AssetLoader`s (within
`AssetLoaders`) using a `HashMap<TypeId, ...>` instead of a `Vec<...>`.
My reasoning for this was I needed to add a relationship between `Asset`
`TypeId`s and the `AssetLoader`, so instead of having a `Vec` and a
`HashMap`, I combined the two, removing the `usize` index from the
adjacent maps.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-31 14:58:08 +00:00
CowSociety
ad0af31b05
Make SavedAsset::get_labeled accept &str as label (#11612)
# Objective

- SavedAsset's iter_labels returns ```&str```, however accessing
LabeledAssets requires ```CowArc<'static, str>```
- Although SavedAsset holds UntypedHandles in its hashmap of
LabeledAssets, they are inaccessible as LabeledAssets are casted to
SavedAsset or ErasedLoadedAsset, which don't contain their
UntypedHandles
- Adresses #11609

## Solution

- Used Trait bounds to allow for either ```CowArc<'static, str>``` or
```&str``` to be used as a label in get_labeled and get_erased_labeled.
- Added method get_untyped_handle to get UntypedHandle from the
LabeledAsset.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-30 22:18:41 +00:00
Gino Valente
379b9e5cb6
bevy_reflect: Split #[reflect(where)] (#11597)
# Objective

Revert the changes to type parameter bounds introduced in #9046,
improves the `#[reflect(where)]` attribute (also from #9046), and adds
the ability to opt out of field bounds.

This is based on suggestions by @soqb and discussion on
[Discord](https://discord.com/channels/691052431525675048/1002362493634629796/1201227833826103427).

## Solution

Reverts the changes to type parameter bounds when deriving `Reflect`,
introduced in #9046. This was originally done as a means of fixing a
recursion issue (#8965). However, as @soqb pointed out, we could achieve
the same result by simply making an opt-out attribute instead of messing
with the type parameter bounds.

This PR has four main changes:
1. Reverts the type parameter bounds from #9046
2. Includes `TypePath` as a default bound for active fields
3. Changes `#reflect(where)]` to be strictly additive
4. Adds `#reflect(no_field_bounds)]` to opt out of field bounds

Change 1 means that, like before, type parameters only receive at most
the `TypePath` bound (if `#[reflect(type_path = false)]` is not present)
and active fields receive the `Reflect` or `FromReflect` bound. And with
Change 2, they will also receive `TypePath` (since it's indirectly
required by `Typed` to construct `NamedField` and `UnnamedField`
instances).

Change 3 was made to make room for Change 4. By splitting out the
responsibility of `#reflect(where)]`, we can use it with or without
`#reflect(no_field_bounds)]` for various use cases.

For example, if we hadn't done this, the following would have failed:

```rust
// Since we're not using `#reflect(no_field_bounds)]`, 
// `T::Assoc` is automatically given the required bounds
// of `FromReflect + TypePath`
#[derive(Reflect)]
#[reflect(where T::Assoc: OtherTrait)]
struct Foo<T: MyTrait> {
  value: T::Assoc,
}
```

This provides more flexibility to the user while still letting them add
or remove most trait bounds.

And to solve the original recursion issue, we can do:

```rust
#[derive(Reflect)]
#[reflect(no_field_bounds)] // <-- Added
struct Foo {
  foo: Vec<Foo>
}
```

#### Bounds

All in all, we now have four sets of trait bounds:
- `Self` gets the bounds `Any + Send + Sync`
- Type parameters get the bound `TypePath`. This can be opted out of
with `#[reflect(type_path = false)]`
- Active fields get the bounds `TypePath` and `FromReflect`/`Reflect`
bounds. This can be opted out of with `#reflect(no_field_bounds)]`
- Custom bounds can be added with `#[reflect(where)]`

---

## Changelog

- Revert some changes #9046
- `#reflect(where)]` is now strictly additive
- Added `#reflect(no_field_bounds)]` attribute to opt out of automatic
field trait bounds when deriving `Reflect`
- Made the `TypePath` requirement on fields when deriving `Reflect` more
explicit

## Migration Guide

> [!important]
> This PR shouldn't be a breaking change relative to the current version
of Bevy (v0.12). And since it removes the breaking parts of #9046, that
PR also won't need a migration guide.
2024-01-29 17:54:17 +00:00
Tristan Guichaoua
b0f5d4df58
Enable the unsafe_op_in_unsafe_fn lint (#11591)
# Objective

- Partial fix of #11590

## Solution

- Enable `unsafe_op_in_unsafe_fn` at workspace level
- Fix the lint for most of the crates
2024-01-28 23:18:11 +00:00
Kanabenki
dad379cdca
Add a getter for asset watching status on AssetServer (#11578)
# Objective

- Closes #11490.
- Allow retrieving the current asset watch behavior from the
`AssetServer`.

## Solution

- Add the corresponding getter. (also fixes some trailing whitespace).

A corresponding helper could also be added on the `AssetPlugin` struct
(returning `self.watch_for_changes_override.unwrap_or(cfg!(feature =
"watch"))`), but it seems it isn't a current practice to have actual
methods on the plugin structs appart from the `Plugin` impl.

---

## Changelog

### Added

Added `watching_for_changes` getter on `AssetServer`.

---------

Co-authored-by: Mateusz Wachowiak <mateusz_wachowiak@outlook.com>
2024-01-28 20:15:14 +00:00
Gino Valente
6e959db134
bevy_reflect: Type parameter bounds (#9046)
# Objective

Fixes #8965.

#### Background

For convenience and to ensure everything is setup properly, we
automatically add certain bounds to the derived types. The current
implementation does this by taking the types from all active fields and
adding them to the where-clause of the generated impls. I believe this
method was chosen because it won't add bounds to types that are
otherwise ignored.

```rust
#[derive(Reflect)]
struct Foo<T, U: SomeTrait, V> {
  t: T,
  u: U::Assoc,
  #[reflect(ignore)]
  v: [V; 2]
}

// Generates something like:
impl<T, U: SomeTrait, V> for Foo<T, U, V>
where
  // Active:
  T: Reflect,
  U::Assoc: Reflect,

  // Ignored:
  [V; 2]: Send + Sync + Any
{
  // ...
}
```

The self-referential type fails because it ends up using _itself_ as a
type bound due to being one of its own active fields.

```rust
#[derive(Reflect)]
struct Foo {
  foo: Vec<Foo>
}

// Foo where Vec<Foo>: Reflect -> Vec<T> where T: Reflect -> Foo where Vec<Foo>: Reflect -> ...
```

## Solution

We can't simply parse all field types for the name of our type. That
would be both complex and prone to errors and false-positives. And even
if it wasn't, what would we replace the bound with?

Instead, I opted to go for a solution that only adds the bounds to what
really needs it: the type parameters. While the bounds on concrete types
make errors a bit cleaner, they aren't strictly necessary. This means we
can change our generated where-clause to only add bounds to generic type
parameters.

Doing this, though, returns us back to the problem of over-bounding
parameters that don't need to be bounded. To solve this, I added a new
container attribute (based on
[this](https://github.com/dtolnay/syn/issues/422#issuecomment-406882925)
comment and @nicopap's
[comment](https://github.com/bevyengine/bevy/pull/9046#issuecomment-1623593780))
that allows us to pass in a custom where clause to modify what bounds
are added to these type parameters.

This allows us to do stuff like:

```rust
trait Trait {
  type Assoc;
}

// We don't need `T` to be reflectable since we only care about `T::Assoc`.
#[derive(Reflect)]
#[reflect(where T::Assoc: FromReflect)]
struct Foo<T: Trait>(T::Assoc);

#[derive(TypePath)]
struct Bar;

impl Trait for Bar {
  type Assoc = usize;
}

#[derive(Reflect)]
struct Baz {
  a: Foo<Bar>,
}
```

> **Note**
> I also
[tried](dc139ea34c)
allowing `#[reflect(ignore)]` to be used on the type parameters
themselves, but that proved problematic since the derive macro does not
consume the attribute. This is why I went with the container attribute
approach.

### Alternatives

One alternative could possibly be to just not add reflection bounds
automatically (i.e. only add required bounds like `Send`, `Sync`, `Any`,
and `TypePath`).

The downside here is we add more friction to using reflection, which
already comes with its own set of considerations. This is a potentially
viable option, but we really need to consider whether or not the
ergonomics hit is worth it.

If we did decide to go the more manual route, we should at least
consider something like #5772 to make it easier for users to add the
right bounds (although, this could still become tricky with
`FromReflect` also being automatically derived).

### Open Questions

1. Should we go with this approach or the manual alternative?
2. ~~Should we add a `skip_params` attribute to avoid the `T: 'static`
trick?~~ ~~Decided to go with `custom_where()` as it's the simplest~~
Scratch that, went with a normal where clause
3. ~~`custom_where` bikeshedding?~~ No longer needed since we are using
a normal where clause

### TODO

- [x] Add compile-fail tests

---

## Changelog

- Fixed issue preventing recursive types from deriving `Reflect`
- Changed how where-clause bounds are generated by the `Reflect` derive
macro
- They are now only applied to the type parameters, not to all active
fields
- Added `#[reflect(where T: Trait, U::Assoc: Trait, ...)]` container
attribute

## Migration Guide

When deriving `Reflect`, generic type params that do not need the
automatic reflection bounds (such as `Reflect`) applied to them will
need to opt-out using a custom where clause like: `#[reflect(where T:
Trait, U::Assoc: Trait, ...)]`.

The attribute can define custom bounds only used by the reflection
impls. To simply opt-out all the type params, we can pass in an empty
where clause: `#[reflect(where)]`.

```rust
// BEFORE:
#[derive(Reflect)]
struct Foo<T>(#[reflect(ignore)] T);

// AFTER:
#[derive(Reflect)]
#[reflect(where)]
struct Foo<T>(#[reflect(ignore)] T);
```

---------

Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2024-01-28 16:24:03 +00:00
thepackett
182c21dc58
AssetPath source parse fix (#11543)
# Objective


Fixes #11533 


When `AssetPath`s are created from a string type, they are parsed into
an `AssetSource`, a `Path`, and a `Label`.
The current method of parsing has some unnecessary quirks:

- The presence of a `:` character is assumed to be the start of an asset
source indicator.
- This is not necessarily true. There are valid uses of a `:` character
in an asset path, for example an http source's port such as
`localhost:80`.
- If there are multiple instances of `://`, the last one is assumed to
be the asset source deliminator.
- This has some unexpected behavior. Even in a fully formed path, such
as `http://localhost:80`, the `:` between `localhost` and `80` is
assumed to be the start of an asset source, causing an error since it
does not form the full sequence `://`.


## Solution
Changes the `AssetPath`'s `parse_internal` method to be more permissive.
- Only the exact sequence `://` is taken to be the asset source
deliminator, and only the first one if there are multiple.
- As a consequence, it is no longer possible to detect a malformed asset
source deliminator, and so the corresponding error was removed.
2024-01-26 21:23:06 +00:00
thepackett
76682fdcb7
AssetSaver and AssetTransformer split (#11260)
# Objective
One of a few Bevy Asset improvements I would like to make: #11216.

Currently asset processing and asset saving are handled by the same
trait, `AssetSaver`. This makes it difficult to reuse saving
implementations and impossible to have a single "universal" saver for a
given asset type.

## Solution
This PR splits off the processing portion of `AssetSaver` into
`AssetTransformer`, which is responsible for transforming assets. This
change involves adding the `LoadTransformAndSave` processor, which
utilizes the new API. The `LoadAndSave` still exists since it remains
useful in situations where no "transformation" of the asset is done,
such as when compressing assets.

## Notes:
As an aside, Bikeshedding is welcome on the names. I'm not entirely
convinced by `AssetTransformer`, which was chosen mostly because
`AssetProcessor` is taken. Additionally, `LoadTransformSave` may be
sufficient instead of `LoadTransformAndSave`.


---

## Changelog
### Added 
- `AssetTransformer` which is responsible for transforming Assets.
- `LoadTransformAndSave`, a `Process` implementation.
### Changed
- Changed `AssetSaver`'s responsibilities from processing and saving to
just saving.
- Updated `asset_processing` example to use new API.
- Old asset .meta files regenerated with new processor.
2024-01-26 20:20:58 +00:00
Ensar Sarajčić
10f95956a6
Fix documentation for AssetReader::is_directory function (#11538)
# Objective

- Fix documentation for `AssetReader::is_directory` (it is currently
exactly the same as docs for `read_directory`)

---------

Co-authored-by: Kanabenki <lucien.menassol@gmail.com>
2024-01-26 13:55:36 +00:00
AxiomaticSemantics
2ebf5a303e
Remove TypeUuid (#11497)
# Objective
TypeUuid is deprecated, remove it.

## Migration Guide
Convert any uses of `#[derive(TypeUuid)]` with `#[derive(TypePath]` for
more complex uses see the relevant
[documentation](https://docs.rs/bevy/latest/bevy/prelude/trait.TypePath.html)
for more information.

---------

Co-authored-by: ebola <dev@axiomatic>
2024-01-25 16:16:58 +00:00
Mark Nevill
d974b8210e
Include asset path in get_meta_path panic message (#11504)
# Objective

- Fixes a hurdle encountered when debugging a panic caused by the file
watcher loading a `.gitignore` file, which was hard to debug because
there was no file name in the report, only `asset paths must have
extensions`

## Solution

- Panic with a formatted message that includes the asset path, e.g.
`missing expected extension for asset path .gitignore`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Doonv <58695417+doonv@users.noreply.github.com>
2024-01-25 08:00:36 +00:00
Jan Hohenheim
02bf4efe64
Fix minor typo (#11491)
"it's type." -> "its type."
2024-01-23 21:00:57 +00:00
BD103
3cfcebcf74
Register AssetPath as type for reflection (#11483)
# Objective

- `AssetPath` implements reflection, but is not registered as a type in
the plugin.
- Fixes #11481.

## Solution

- Register the `AssetPath` type when `AssetPlugin::build` is called.

---

## Changelog

- Registered `AssetPath` type for use in reflection.
2024-01-23 04:30:44 +00:00
François
259fb6896e
auto create imported asset folder if needed (#11284)
# Objective

- Since #11218, example `asset_processing` fails:
```
thread 'main' panicked at crates/bevy_asset/src/io/source.rs:489:18:
Failed to create file watcher: Error { kind: PathNotFound, paths: ["examples/asset/processing/imported_assets/Default"] }
```

start from a fresh git clone or delete the folder before running to
reproduce, it is in gitignore and should not be present on a fresh run

a657478675/.gitignore (L18)

## Solution

- Auto create the `imported_assets` folder if it is configured

---------

Co-authored-by: Kyle <37520732+nvdaz@users.noreply.github.com>
2024-01-21 09:30:43 +00:00
Brian Reavis
c9e1fcdb35
Added AssetLoadFailedEvent, UntypedAssetLoadFailedEvent (#11369)
# Objective

This adds events for assets that fail to load along with minor utility
methods to make them useful. This paves the way for users writing their
own error handling and retry systems, plus Bevy including robust retry
handling: #11349.

* Addresses #11288
* Needed for #11349

# Solution

```rust
/// An event emitted when a specific [`Asset`] fails to load.
#[derive(Event, Clone, Debug)]
pub struct AssetLoadFailedEvent<A: Asset> {
    pub id: AssetId<A>,
    /// The original handle returned when the asset load was requested.
    pub handle: Option<Handle<A>>,
    /// The asset path that was attempted.
    pub path: AssetPath<'static>,
    /// Why the asset failed to load.
    pub error: AssetLoadError,
}
```

I started implementing `AssetEvent::Failed` like suggested in #11288,
but decided it was better as its own type because:

* I think it makes sense for `AssetEvent` to only refer to assets that
actually exist.
* In order to return `AssetLoadError` in the event (which is useful
information for error handlers that might attempt a retry) we would have
to remove `Copy` from `AssetEvent`.
* There are numerous places in the render app that match against
`AssetEvent`, and I don't think it's worth introducing extra noise about
assets that don't exist.

I also introduced `UntypedAssetLoadErrorEvent`, which is very useful in
places that need to support type flexibility, like an Asset-agnostic
retry plugin.

# Changelog

* **Added:** `AssetLoadFailedEvent<A>`
* **Added**: `UntypedAssetLoadFailedEvent`
* **Added:** `AssetReaderError::Http` for status code information on
HTTP errors. Before this, status codes were only available by parsing
the error message of generic `Io` errors.
* **Added:** `asset_server.get_path_id(path)`. This method simply gets
the asset id for the path. Without this, one was left using
`get_path_handle(path)`, which has the overhead of returning a strong
handle.
* **Fixed**: Made `AssetServer` loads return the same handle for assets
that already exist in a failed state. Now, when you attempt a `load`
that's in a `LoadState::Failed` state, it'll re-use the original asset
id. The advantage of this is that any dependent assets created using the
original handle will "unbreak" if a retry succeeds.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-17 21:12:00 +00:00
Shane Celis
b6e154fc64
Fix embedded watcher to work with external crates (#11370)
# Objective

Tried using "embedded_watcher" feature and `embedded_asset!()` from
another crate. The assets embedded fine but were not "watched." The
problem appears to be that checking for the feature was done inside the
macro, so rather than checking if "embedded_watcher" was enabled for
bevy, it would check if it was enabled for the current crate.

## Solution

I extracted the checks for the "embedded_watcher" feature into its own
function called `watched_path()`. No external changes.

### Alternative Solution

An alternative fix would be to not do any feature checking in
`embedded_asset!()` or an extracted function and always send the
full_path to `insert_asset()` where it's promptly dropped when the
feature isn't turned on. That would be simpler.

```
    ($app: ident, $source_path: expr, $path: expr) => {{
        let mut embedded = $app
            .world
            .resource_mut::<$crate::io::embedded::EmbeddedAssetRegistry>();
        let path = $crate::embedded_path!($source_path, $path);
        //#[cfg(feature = "embedded_watcher")]
        let full_path = std::path::Path::new(file!()).parent().unwrap().join($path);
        //#[cfg(not(feature = "embedded_watcher"))]
        //let full_path = std::path::PathBuf::new();
        embedded.insert_asset(full_path, &path, include_bytes!($path));
    }};
```

## Changelog

> Fix embedded_watcher feature to work with external crates
2024-01-16 15:18:16 +00:00
Stepan Koltsov
c0f8338697
Better error message on incorrect asset label (#11254)
# Objective

When you have no idea what to put after `#` when loading an asset, error
message may help.

## Solution

Add all labels to the error message.

## Test plan

Modified `anti_alias` example to put incorrect label, the error is:

```
2024-01-08T07:41:25.462287Z ERROR bevy_asset::server: The file at 'models/FlightHelmet/FlightHelmet.gltf' does not contain the labeled asset 'Rrrr'; it contains the following 25 assets: 'Material0', 'Material1', 'Material2', 'Material3', 'Material4', 'Material5', 'Mesh0', 'Mesh0/Primitive0', 'Mesh1', 'Mesh1/Primitive0', 'Mesh2', 'Mesh2/Primitive0', 'Mesh3', 'Mesh3/Primitive0', 'Mesh4', 'Mesh4/Primitive0', 'Mesh5', 'Mesh5/Primitive0', 'Node0', 'Node1', 'Node2', 'Node3', 'Node4', 'Node5', 'Scene0'
```
2024-01-08 22:45:07 +00:00
andriyDev
da485c29b3
Add reserve_handle to Assets. (#10939)
# Objective

Fixes #10938.

## Solution

Adds `reserve_handle` to `Assets`.

---

## Changelog

- Added `reserve_handle` to `Assets`.
2024-01-08 22:17:29 +00:00
Joona Aalto
a795de30b4
Use impl Into<A> for Assets::add (#10878)
# Motivation

When spawning entities into a scene, it is very common to create assets
like meshes and materials and to add them via asset handles. A common
setup might look like this:

```rust
fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn(PbrBundle {
        mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
        material: materials.add(StandardMaterial::from(Color::RED)),
        ..default()
    });
}
```

Let's take a closer look at the part that adds the assets using `add`.

```rust
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(StandardMaterial::from(Color::RED)),
```

Here, "mesh" and "material" are both repeated three times. It's very
explicit, but I find it to be a bit verbose. In addition to being more
code to read and write, the extra characters can sometimes also lead to
the code being formatted to span multiple lines even though the core
task, adding e.g. a primitive mesh, is extremely simple.

A way to address this is by using `.into()`:

```rust
mesh: meshes.add(shape::Cube { size: 1.0 }.into()),
material: materials.add(Color::RED.into()),
```

This is fine, but from the names and the type of `meshes`, we already
know what the type should be. It's very clear that `Cube` should be
turned into a `Mesh` because of the context it's used in. `.into()` is
just seven characters, but it's so common that it quickly adds up and
gets annoying.

It would be nice if you could skip all of the conversion and let Bevy
handle it for you:

```rust
mesh: meshes.add(shape::Cube { size: 1.0 }),
material: materials.add(Color::RED),
```

# Objective

Make adding assets more ergonomic by making `Assets::add` take an `impl
Into<A>` instead of `A`.

## Solution

`Assets::add` now takes an `impl Into<A>` instead of `A`, so e.g. this
works:

```rust
    commands.spawn(PbrBundle {
        mesh: meshes.add(shape::Cube { size: 1.0 }),
        material: materials.add(Color::RED),
        ..default()
    });
```

I also changed all examples to use this API, which increases consistency
as well because `Mesh::from` and `into` were being used arbitrarily even
in the same file. This also gets rid of some lines of code because
formatting is nicer.

---

## Changelog

- `Assets::add` now takes an `impl Into<A>` instead of `A`
- Examples don't use `T::from(K)` or `K.into()` when adding assets

## Migration Guide

Some `into` calls that worked previously might now be broken because of
the new trait bounds. You need to either remove `into` or perform the
conversion explicitly with `from`:

```rust
// Doesn't compile
let mesh_handle = meshes.add(shape::Cube { size: 1.0 }.into()),

// These compile
let mesh_handle = meshes.add(shape::Cube { size: 1.0 }),
let mesh_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
```

## Concerns

I believe the primary concerns might be:

1. Is this too implicit?
2. Does this increase codegen bloat?

Previously, the two APIs were using `into` or `from`, and now it's
"nothing" or `from`. You could argue that `into` is slightly more
explicit than "nothing" in cases like the earlier examples where a
`Color` gets converted to e.g. a `StandardMaterial`, but I personally
don't think `into` adds much value even in this case, and you could
still see the actual type from the asset type.

As for codegen bloat, I doubt it adds that much, but I'm not very
familiar with the details of codegen. I personally value the user-facing
code reduction and ergonomics improvements that these changes would
provide, but it might be worth checking the other effects in more
detail.

Another slight concern is migration pain; apps might have a ton of
`into` calls that would need to be removed, and it did take me a while
to do so for Bevy itself (maybe around 20-40 minutes). However, I think
the fact that there *are* so many `into` calls just highlights that the
API could be made nicer, and I'd gladly migrate my own projects for it.
2024-01-08 22:14:43 +00:00
Kyle
2847cc6933
Don't auto create assets folder (#11218)
# Objective

- Don't automatically create an assets folder
- resolves #11208

## Solution

- Removes directory creation from file reader.
- Clearer panic when using file watcher and asset folder doesn't exist

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2024-01-08 21:45:26 +00:00
JMS55
44424391fe
Unload render assets from RAM (#10520)
# Objective
- No point in keeping Meshes/Images in RAM once they're going to be sent
to the GPU, and kept in VRAM. This saves a _significant_ amount of
memory (several GBs) on scenes like bistro.
- References
  - https://github.com/bevyengine/bevy/pull/1782
  - https://github.com/bevyengine/bevy/pull/8624 

## Solution
- Augment RenderAsset with the capability to unload the underlying asset
after extracting to the render world.
- Mesh/Image now have a cpu_persistent_access field. If this field is
RenderAssetPersistencePolicy::Unload, the asset will be unloaded from
Assets<T>.
- A new AssetEvent is sent upon dropping the last strong handle for the
asset, which signals to the RenderAsset to remove the GPU version of the
asset.

---

## Changelog
- Added `AssetEvent::NoLongerUsed` and
`AssetEvent::is_no_longer_used()`. This event is sent when the last
strong handle of an asset is dropped.
- Rewrote the API for `RenderAsset` to allow for unloading the asset
data from the CPU.
- Added `RenderAssetPersistencePolicy`.
- Added `Mesh::cpu_persistent_access` for memory savings when the asset
is not needed except for on the GPU.
- Added `Image::cpu_persistent_access` for memory savings when the asset
is not needed except for on the GPU.
- Added `ImageLoaderSettings::cpu_persistent_access`.
- Added `ExrTextureLoaderSettings`.
- Added `HdrTextureLoaderSettings`.

## Migration Guide
- Asset loaders (GLTF, etc) now load meshes and textures without
`cpu_persistent_access`. These assets will be removed from
`Assets<Mesh>` and `Assets<Image>` once `RenderAssets<Mesh>` and
`RenderAssets<Image>` contain the GPU versions of these assets, in order
to reduce memory usage. If you require access to the asset data from the
CPU in future frames after the GLTF asset has been loaded, modify all
dependent `Mesh` and `Image` assets and set `cpu_persistent_access` to
`RenderAssetPersistencePolicy::Keep`.
- `Mesh` now requires a new `cpu_persistent_access` field. Set it to
`RenderAssetPersistencePolicy::Keep` to mimic the previous behavior.
- `Image` now requires a new `cpu_persistent_access` field. Set it to
`RenderAssetPersistencePolicy::Keep` to mimic the previous behavior.
- `MorphTargetImage::new()` now requires a new `cpu_persistent_access`
parameter. Set it to `RenderAssetPersistencePolicy::Keep` to mimic the
previous behavior.
- `DynamicTextureAtlasBuilder::add_texture()` now requires that the
`TextureAtlas` you pass has an `Image` with `cpu_persistent_access:
RenderAssetPersistencePolicy::Keep`. Ensure you construct the image
properly for the texture atlas.
- The `RenderAsset` trait has significantly changed, and requires
adapting your existing implementations.
  - The trait now requires `Clone`.
- The `ExtractedAsset` associated type has been removed (the type itself
is now extracted).
  - The signature of `prepare_asset()` is slightly different
- A new `persistence_policy()` method is now required (return
RenderAssetPersistencePolicy::Unload to match the previous behavior).
- Match on the new `NoLongerUsed` variant for exhaustive matches of
`AssetEvent`.
2024-01-03 03:31:04 +00:00
Doonv
189ceaf0d3
Replace or document ignored doctests (#11040)
# Objective

There are a lot of doctests that are `ignore`d for no documented reason.
And that should be fixed.

## Solution

I searched the bevy repo with the regex ` ```[a-z,]*ignore ` in order to
find all `ignore`d doctests. For each one of the `ignore`d doctests, I
did the following steps:
1. Attempt to remove the `ignored` attribute while still passing the
test. I did this by adding hidden dummy structs and imports.
2. If step 1 doesn't work, attempt to replace the `ignored` attribute
with the `no_run` attribute while still passing the test.
3. If step 2 doesn't work, keep the `ignored` attribute but add
documentation for why the `ignored` attribute was added.

---------

Co-authored-by: François <mockersf@gmail.com>
2024-01-01 16:50:56 +00:00
Tygyh
1568d4a415
Reorder impl to be the same as the trait (#11076)
# Objective

- Make the implementation order consistent between all sources to fit
the order in the trait.

## Solution

- Change the implementation order.
2023-12-24 17:43:55 +00:00
Tygyh
7b8305e5b4
Remove unnecessary parens (#11075)
# Objective

- Increase readability.

## Solution

- Remove unnecessary parens.
2023-12-24 17:43:01 +00:00
Thierry Berger
ced216f59a
Update winit dependency to 0.29 (#10702)
# Objective

- Update winit dependency to 0.29

## Changelog

### KeyCode changes

- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.

KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.

In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.

### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)

## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔

## Follow up 

I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
  - blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
  - fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
    - [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
  - we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide

This PR should have one.
2023-12-21 07:40:47 +00:00
Tygyh
696af48416
Remove unnecessary parentheses (#10990)
# Objective

- Increase readability.

## Solution

- Remove unnecessary parentheses.
2023-12-16 02:26:18 +00:00
Mateusz Wachowiak
a7a5d17ae1
Refactor process_handle_drop_internal() in bevy_asset (#10920)
# Objective

- Reduce nesting in `process_handle_drop_internal()`.
- Related to #10896.

## Solution

- Use early returns when possible.
- Reduced from 9 levels of indents to 4.
2023-12-12 19:46:37 +00:00
Carter Anderson
0a588dbfd9
Allow removing and reloading assets with live handles (#10785)
# Objective

Fixes #10444 

Currently manually removing an asset prevents it from being reloaded
while there are still active handles. Doing so will result in a panic,
because the storage entry has been marked as "empty / None" but the ID
is still assumed to be active by the asset server.

Patterns like `images.remove() -> asset_server.reload()` and
`images.remove() -> images.insert()` would fail if the handle was still
alive.

## Solution

Most of the groundwork for this was already laid in Bevy Asset V2. This
is largely just a matter of splitting out `remove` into two separate
operations:

* `remove_dropped`: remove the stored asset, invalidate the internal
Assets entry (preventing future insertions with the old id), and recycle
the id
* `remove_still_alive`: remove the stored asset, but leave the entry
otherwise untouched (and dont recycle the id).

`remove_still_alive` and `insert` can be called any number of times (in
any order) for an id until `remove_dropped` has been called, which will
invalidate the id.

From a user-facing perspective, there are no API changes and this is non
breaking. The public `Assets::remove` will internally call
`remove_still_alive`. `remove_dropped` can only be called by the
internal "handle management" system.

---

## Changelog

- Fix a bug preventing `Assets::remove` from blocking future inserts for
a specific `AssetIndex`.
2023-11-29 23:32:13 +00:00
Carter Anderson
4221f7e7e9
Print precise and correct watch warnings (and only when necessary) (#10787)
# Objective

Fixes #10401 

## Solution

* Allow sources to register specific processed/unprocessed watch
warnings.
* Specify per-platform watch warnings. This removes the need to cover
all platform cases in one warning message.
* Only register watch warnings for the _processed_ embedded source, as
warning about watching unprocessed embedded isn't helpful.

---

## Changelog

- Asset sources can now register specific watch warnings.
2023-11-29 00:35:13 +00:00
tygyh
fd308571c4
Remove unnecessary path prefixes (#10749)
# Objective

- Shorten paths by removing unnecessary prefixes

## Solution

- Remove the prefixes from many paths which do not need them. Finding
the paths was done automatically using built-in refactoring tools in
Jetbrains RustRover.
2023-11-28 23:43:40 +00:00
Kanabenki
0e9f6e92ea
Add clippy::manual_let_else at warn level to lints (#10684)
# Objective

Related to #10612.

Enable the
[`clippy::manual_let_else`](https://rust-lang.github.io/rust-clippy/master/#manual_let_else)
lint as a warning. The `let else` form seems more idiomatic to me than a
`match`/`if else` that either match a pattern or diverge, and from the
clippy doc, the lint doesn't seem to have any possible false positive.

## Solution

Add the lint as warning in `Cargo.toml`, refactor places where the lint
triggers.
2023-11-28 04:15:27 +00:00
Carter Anderson
cc6c4d65ed
Fix GLTF scene dependencies and make full scene renders predictable (#10745)
# Objective

Fixes #10688

There were a number of issues at play:

1. The GLTF loader was not registering Scene dependencies properly. They
were being registered at the root instead of on the scene assets. This
made `LoadedWithDependencies` fire immediately on load.
2. Recursive labeled assets _inside_ of labeled assets were not being
loaded. This only became relevant for scenes after fixing (1) because we
now add labeled assets to the nested scene `LoadContext` instead of the
root load context. I'm surprised nobody has hit this yet. I'm glad I
caught it before somebody hit it.
3. Accessing "loaded with dependencies" state on the Asset Server is
boilerplatey + error prone (because you need to manually query two
states).

## Solution

1. In GltfLoader, use a nested LoadContext for scenes and load
dependencies through that context.
2. In the `AssetServer`, load labeled assets recursively.
3. Added a simple `asset_server.is_loaded_with_dependencies(id)`

I also added some docs to `LoadContext` to help prevent this problem in
the future.

---

## Changelog

- Added `AssetServer::is_loaded_with_dependencies`
- Fixed GLTF Scene dependencies
- Fixed nested labeled assets not being loaded

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-11-27 22:42:28 +00:00
Carter Anderson
fa903a122f
AssetMetaMode (#10623)
# Objective

Fixes #10157

## Solution

Add `AssetMetaCheck` resource which can configure when/if asset meta
files will be read:

```rust
app
  // Never attempts to look up meta files. The default meta configuration will be used for each asset.
  .insert_resource(AssetMetaCheck::Never)
  .add_plugins(DefaultPlugins)
```


This serves as a band-aid fix for the issue with wasm's
`HttpWasmAssetReader` creating a bunch of requests for non-existent
meta, which can slow down asset loading (by waiting for the 404
response) and creates a bunch of noise in the logs. This also provides a
band-aid fix for the more serious issue of itch.io deployments returning
403 responses, which results in full failure of asset loads.

If users don't want to include meta files for all deployed assets for
web builds, and they aren't using meta files at all, they should set
this to `AssetMetaCheck::Never`.

If users do want to include meta files for specific assets, they can use
`AssetMetaCheck::Paths`, which will only look up meta for those paths.

Currently, this defaults to `AssetMetaCheck::Always`, which makes this
fully non-breaking for the `0.12.1` release. _**However it _is_ worth
discussing making this `AssetMetaCheck::Never` by default**_, given that
I doubt most people are using meta files without the Asset Processor
enabled. This would be a breaking change, but it would make WASM / Itch
deployments work by default, which is a pretty big win imo. The downside
is that people using meta files _without_ processing would need to
manually enable `AssetMetaCheck::Always`, which is also suboptimal.

When in `AssetMetaCheck::Processed`, the meta check resource is ignored,
as processing requires asset meta files to function.

In general, I don't love adding this knob as things should ideally "just
work" in all cases. But this is the reality of the current situation.

---

## Changelog

- Added `AssetMetaCheck` resource, which can configure when/if asset
meta files will be read
2023-11-27 22:32:36 +00:00
Mike
11b1b3a24f
delete methods deprecated in 0.12 (#10693)
## Changelog

- delete methods deprecated in 0.12
2023-11-24 16:15:47 +00:00
Lixou
960f6e9131
remove double-hasing of typeid for handle (#10699)
# Objective

There is a double hash for the typeid for asset handles. (see
[this](https://github.com/bevyengine/bevy/issues/10695#issuecomment-1822340727)
for more info)

## Solution

- Remove the second hash of the typeid
2023-11-23 01:04:37 +00:00
Zachary Harrold
f613c450bc
Fix Asset Loading Bug (#10698)
# Objective

- Fixes #10695

## Solution

Fixed obvious blunder in `PartialEq` implementation for
`UntypedAssetId`'s where the `TypeId` was not included in the
comparison. This was not picked up in the unit tests I added because
they only tested over a single asset type.
2023-11-22 13:39:44 +00:00
Zachary Harrold
57a175f546
Ensure consistency between Un/Typed AssetId and Handle (#10628)
# Objective

- Fixes #10629
- `UntypedAssetId` and `AssetId` (along with `UntypedHandle` and
`Handle`) do not hash to the same values when pointing to the same
`Asset`. Additionally, comparison and conversion between these types
does not follow idiomatic Rust standards.

## Solution

- Added new unit tests to validate/document expected behaviour
- Added trait implementations to make working with Un/Typed values more
ergonomic
- Ensured hashing and comparison between Un/Typed values is consistent
- Removed `From` trait implementations that panic, and replaced them
with `TryFrom`

---

## Changelog

- Ensured `Handle::<A>::hash` and `UntypedHandle::hash` will produce the
same value for the same `Asset`
- Added non-panicing `Handle::<A>::try_typed`
- Added `PartialOrd` to `UntypedHandle` to match `Handle<A>` (this will
return `None` for `UntypedHandles` for differing `Asset` types)
- Added `TryFrom<UntypedHandle>` for `Handle<A>`
- Added `From<Handle<A>>` for `UntypedHandle`
- Removed panicing `From<Untyped...>` implementations. These are
currently unused within the Bevy codebase, and shouldn't be used
externally, hence removal.
- Added cross-implementations of `PartialEq` and `PartialOrd` for
`UntypedHandle` and `Handle<A>` allowing direct comparison when
`TypeId`'s match.
- Near-identical changes to `AssetId` and `UntypedAssetId`

## Migration Guide

If you relied on any of the panicing `From<Untyped...>` implementations,
simply call the existing `typed` methods instead. Alternatively, use the
new `TryFrom` implementation instead to directly expose possible
mistakes.

## Notes

I've made these changes since `Handle` is such a fundamental type to the
entire `Asset` ecosystem within Bevy, and yet it had pretty unclear
behaviour with no direct testing. The fact that hashing untyped vs typed
versions of the same handle would produce different values is something
I expect to cause a very subtle bug for someone else one day.

I haven't included it in this PR to avoid any controversy, but I also
believe the `typed_unchecked` methods should be removed from these
types, or marked as `unsafe`. The `texture_atlas` example currently uses
it, and I believe it is a bad choice. The performance gained by not
type-checking before conversion would be entirely dwarfed by the act of
actually loading an asset and creating its handle anyway. If an end user
is in a tight loop repeatedly calling `typed_unchecked` on an
`UntypedHandle` for the entire runtime of their application, I think the
small performance drop caused by that safety check is ~~a form of cosmic
justice~~ reasonable.
2023-11-21 01:13:36 +00:00
robtfm
7ff61a8dc9
derive asset for enums (#10410)
# Objective

allow deriving `Asset` for enums, and for tuple structs.

## Solution

add to the proc macro, generating visitor calls to the variant's data
(if required).

supports unnamed or named field variants, and struct variants when the
struct also derives `Asset`:
```rust
#[derive(Asset, TypePath)]
pub enum MyAssetEnum {
    Unnamed (
        #[dependency]
        Handle<Image>
    ),
    Named {
        #[dependency]
        array_handle: Handle<Image>,
        #[dependency]
        atlas_handles: Vec<Handle<Image>>,
    },
    StructStyle(
        #[dependency]
        VariantStruct
    ),
    Empty,
}

#[derive(Asset, TypePath)]
pub struct VariantStruct {
    // ...
}
```

also extend the struct implementation to support tuple structs: 
```rust
#[derive(Asset, TypePath)]
pub struct MyImageNewtype(
    #[dependency]
    Handle<Image>
);
````

---------

Co-authored-by: Nicola Papale <nico@nicopap.ch>
2023-11-21 01:06:55 +00:00
Nicola Papale
96444b24fd
Fix file_watcher feature hanging indefinitely (#10585)
# Objective

Fix the `bevy_asset/file_watcher` feature in practice depending on
multithreading, while not informing the user of it.

**As I understand it** (I didn't check it), the file watcher feature
depends on spawning a concurrent thread to receive file update events
from the `notify-debouncer-full` crate. But if multithreading is
disabled, that thread will never have time to read the events and
consume them.

- Fixes #10573 


## Solution

Add a `compile_error!` causing compilation failure if `file_watcher` is
enabled while `multi-threaded` is disabled.

This is considered better than adding a dependency on `multi-threaded`
on the `file_watcher`, as (according to @mockersf) toggling on/off
`multi-threaded` has a non-zero chance of changing behavior. And we
shouldn't implicitly change behavior. A compilation failure prevents
compilation of code that is invalid, while informing the user of the
steps needed to fix it.
2023-11-20 09:43:43 +00:00
Ame
951c9bb1a2
Add [lints] table, fix adding #![allow(clippy::type_complexity)] everywhere (#10011)
# Objective

- Fix adding `#![allow(clippy::type_complexity)]` everywhere. like #9796

## Solution

- Use the new [lints] table that will land in 1.74
(https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints)
- inherit lint to the workspace, crates and examples.
```
[lints]
workspace = true
```

## Changelog

- Bump rust version to 1.74
- Enable lints table for the workspace
```toml
[workspace.lints.clippy]
type_complexity = "allow"
```
- Allow type complexity for all crates and examples
```toml
[lints]
workspace = true
```

---------

Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
2023-11-18 20:58:48 +00:00
Michael Leandersson
9a909f593a
Do not panic when failing to create assets folder (#10613) (#10614)
# Objective

- Allow bevy applications that does not have any assets folder to start
from a read-only directory. (typically installed to a systems folder)

Fixes #10613

## Solution

- warn instead of panic when assets folder creation fails.
2023-11-17 22:06:08 +00:00
MevLyshkin
2b32de9ba2
Fix wasm builds with file_watcher enabled (#10589)
# Objective

- Currently, in 0.12 there is an issue that it is not possible to build
bevy for Wasm with feature "file_watcher" enabled. It still would not
compile, but now with proper explanation.
- Fixes https://github.com/bevyengine/bevy/issues/10507


## Solution

- Remove `notify-debouncer-full` dependency on WASM platform entirely.
- Compile with "file_watcher" feature now on platform `wasm32` gives
meaningful compile error.

---

## Changelog

### Fixed

- Compile with "file_watcher" feature now on platform `wasm32` gives
meaningful compile error.
2023-11-17 22:04:42 +00:00
Carter Anderson
c7f5cec8be
Add missing asset load error logs for load_folder and load_untyped (#10578)
# Objective

Fixes #10515 

## Solution

Add missing error logs.
2023-11-16 21:31:20 +00:00
Zachary Harrold
46b8e904f4
Added Method to Allow Pipelined Asset Loading (#10565)
# Objective

- Fixes #10518

## Solution

I've added a method to `LoadContext`, `load_direct_with_reader`, which
mirrors the behaviour of `load_direct` with a single key difference: it
is provided with the `Reader` by the caller, rather than getting it from
the contained `AssetServer`. This allows for an `AssetLoader` to process
its `Reader` stream, and then directly hand the results off to the
`LoadContext` to handle further loading. The outer `AssetLoader` can
control how the `Reader` is interpreted by providing a relevant
`AssetPath`.

For example, a Gzip decompression loader could process the asset
`images/my_image.png.gz` by decompressing the bytes, then handing the
decompressed result to the `LoadContext` with the new path
`images/my_image.png.gz/my_image.png`. This intuitively reflects the
nature of contained assets, whilst avoiding unintended behaviour, since
the generated path cannot be a real file path (a file and folder of the
same name cannot coexist in most file-systems).

```rust
#[derive(Asset, TypePath)]
pub struct GzAsset {
    pub uncompressed: ErasedLoadedAsset,
}

#[derive(Default)]
pub struct GzAssetLoader;

impl AssetLoader for GzAssetLoader {
    type Asset = GzAsset;
    type Settings = ();
    type Error = GzAssetLoaderError;
    fn load<'a>(
        &'a self,
        reader: &'a mut Reader,
        _settings: &'a (),
        load_context: &'a mut LoadContext,
    ) -> BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
        Box::pin(async move {
            let compressed_path = load_context.path();
            let file_name = compressed_path
                .file_name()
                .ok_or(GzAssetLoaderError::IndeterminateFilePath)?
                .to_string_lossy();
            let uncompressed_file_name = file_name
                .strip_suffix(".gz")
                .ok_or(GzAssetLoaderError::IndeterminateFilePath)?;
            let contained_path = compressed_path.join(uncompressed_file_name);

            let mut bytes_compressed = Vec::new();

            reader.read_to_end(&mut bytes_compressed).await?;

            let mut decoder = GzDecoder::new(bytes_compressed.as_slice());

            let mut bytes_uncompressed = Vec::new();

            decoder.read_to_end(&mut bytes_uncompressed)?;

            // Now that we have decompressed the asset, let's pass it back to the
            // context to continue loading

            let mut reader = VecReader::new(bytes_uncompressed);

            let uncompressed = load_context
                .load_direct_with_reader(&mut reader, contained_path)
                .await?;

            Ok(GzAsset { uncompressed })
        })
    }

    fn extensions(&self) -> &[&str] {
        &["gz"]
    }
}
```

Because this example is so prudent, I've included an
`asset_decompression` example which implements this exact behaviour:

```rust
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_asset::<GzAsset>()
        .init_asset_loader::<GzAssetLoader>()
        .add_systems(Startup, setup)
        .add_systems(Update, decompress::<Image>)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2dBundle::default());

    commands.spawn((
        Compressed::<Image> {
            compressed: asset_server.load("data/compressed_image.png.gz"),
            ..default()
        },
        Sprite::default(),
        TransformBundle::default(),
        VisibilityBundle::default(),
    ));
}

fn decompress<A: Asset>(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut compressed_assets: ResMut<Assets<GzAsset>>,
    query: Query<(Entity, &Compressed<A>)>,
) {
    for (entity, Compressed { compressed, .. }) in query.iter() {
        let Some(GzAsset { uncompressed }) = compressed_assets.remove(compressed) else {
            continue;
        };

        let uncompressed = uncompressed.take::<A>().unwrap();

        commands
            .entity(entity)
            .remove::<Compressed<A>>()
            .insert(asset_server.add(uncompressed));
    }
}
```

A key limitation to this design is how to type the internally loaded
asset, since the example `GzAssetLoader` is unaware of the internal
asset type `A`. As such, in this example I store the contained asset as
an `ErasedLoadedAsset`, and leave it up to the consumer of the `GzAsset`
to handle typing the final result, which is the purpose of the
`decompress` system. This limitation can be worked around by providing
type information to the `GzAssetLoader`, such as `GzAssetLoader<Image,
ImageAssetLoader>`, but this would require registering the asset loader
for every possible decompression target.

Aside from this limitation, nested asset containerisation works as an
end user would expect; if the user registers a `TarAssetLoader`, and a
`GzAssetLoader`, then they can load assets with compound
containerisation, such as `images.tar.gz`.

---

## Changelog

- Added `LoadContext::load_direct_with_reader`
- Added `asset_decompression` example

## Notes

- While I believe my implementation of a Gzip asset loader is
reasonable, I haven't included it as a public feature of `bevy_asset` to
keep the scope of this PR as focussed as possible.
- I have included `flate2` as a `dev-dependency` for the example; it is
not included in the main dependency graph.
2023-11-16 17:47:31 +00:00
orph3usLyre
a2d90a8533
ReadAssetBytesError::Io exposes failing path (#10450)
# Objective

Addresses #[10438](https://github.com/bevyengine/bevy/issues/10438)

The objective was to include the failing path in the error for the user
to see.

## Solution

Add a `path` field to the `ReadAssetBytesError::Io` variant to expose
the failing path in the error message.

## Migration Guide
- The `ReadAssetBytesError::Io` variant now contains two named fields
instead of converting from `std::io::Error`.
    1. `path`: The requested (failing) path (`PathBuf`)
    2. `source`: The source `std::io::Error`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-11-16 17:41:37 +00:00
Testare
675aac97e5
Add load_untyped to LoadContext (#10526)
# Objective

Give us the ability to load untyped assets in AssetLoaders.

## Solution

Basically just copied the code from `load`, but used
`asset_server.load_untyped` instead internally.

## Changelog

Added `load_untyped` method to `LoadContext`
2023-11-15 22:31:33 +00:00
Joseph
dcfae72386
Re-export ron in bevy_scene (#10529)
# Objective

Close #10504. Improve the development experience for working with scenes
by not requiring the user to specify a matching version of `ron` in
their `Cargo.toml`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-11-15 14:45:54 +00:00
Carter Anderson
749f3d7430
Fix untyped labeled asset loading (#10514)
# Objective

Fixes #10436
Alternative to #10465 

## Solution

`load_untyped_async` / `load_internal` currently has a bug. In
`load_untyped_async`, we pass None into `load_internal` for the
`UntypedHandle` of the labeled asset path. This results in a call to
`get_or_create_path_handle_untyped` with `loader.asset_type_id()`
This is a new code path that wasn't hit prior to the newly added
`load_untyped` because `load_untyped_async` was a private method only
used in the context of the `load_folder` impl (which doesn't have
labels)

The fix required some refactoring to catch that case and defer handle
retrieval. I have also made `load_untyped_async` public as it is now
"ready for public use" and unlocks new scenarios.
2023-11-14 02:41:10 +00:00
Waridley
9f4c3e943a
Prepend root_path to meta path in HttpWasmAssetReader (#10527)
# Objective

Fixes an issue where Bevy will look for `.meta` files in the root of the
server instead of `imported_assets/Default` on the web.

## Solution

`self.root_path.join` was seemingly forgotten in the `read_meta`
function on `HttpWasmAssetReader`, though it was included in the `read`
function. This PR simply adds the missing function call.
2023-11-14 01:29:22 +00:00
Rafał Harabień
e3a59c480d
Make AssetLoader/Saver Error type bounds compatible with anyhow::Error (#10493)
# Objective

* In Bevy 0.11 asset loaders used `anyhow::Error` for returning errors.
In Bevy 0.12 `AssetLoader` (and `AssetSaver`) have associated `Error`
type. Unfortunately it's type bounds does not allow `anyhow::Error` to
be used despite migration guide claiming otherwise. This makes migration
to 0.12 more challenging. Solve this by changing type bounds for
associated `Error` type.
* Fix #10350

## Solution

Change associated `Error` type bounds to require `Into<Box<dyn
std::error::Error + Send + Sync + 'static>>` to be implemented instead
of `std::error::Error + Send + Sync + 'static`. Both `anyhow::Error` and
errors generated by `thiserror` seems to be fine with such type bound.

---

## Changelog

### Fixed
* Fixed compatibility with `anyhow::Error` in `AssetLoader` and
`AssetSaver` associated `Error` type
2023-11-14 01:25:06 +00:00
Connor King
bf4f4e42da
use tree syntax to explain bevy_rock file structure (#10523)
# Objective

The current way it's written is just kinda hard to read

![image](https://github.com/bevyengine/bevy/assets/14184826/3102f50a-9220-4f86-99e0-41ea23822ea7)


## Solution

the box-drawing characters stolen from `tree`

![image](https://github.com/bevyengine/bevy/assets/14184826/e66c027b-ed69-469d-a0ee-1d73e2c7be18)

---

would've added this to my previous PR but i woke up this morning and it
was merged
2023-11-12 17:11:26 +00:00
Connor King
51180f81a2
Remove rogue : from embedded_asset! docs (#10516)
# Objective

- Fix a random typo I noticed in the docs of `embedded_asset`

## Solution

- fixed the typo
2023-11-12 14:51:35 +00:00
Spencer C. Imbleau
2a036b658f
feat: Debug implemented for AssetMode (#10494)
# Objective

- Implements Debug for AssetMode

Closes #10473

Co-authored-by: Sebastian Hamel <sebastian@jhamel.com>
2023-11-10 21:38:46 +00:00
Sludge
13d46a528a
Don't .unwrap() in AssetPath::try_parse (#10452)
# Objective

- The docs on `AssetPath::try_parse` say that it will return an error
when the string is malformed, but it actually just `.unwrap()`s the
result.

## Solution

- Use `?` instead of unwrapping the result.
2023-11-09 18:07:48 +00:00
François
49bc6cfd62
support file operations in single threaded context (#10312)
# Objective

- Fixes #10209 
- Assets should work in single threaded

## Solution

- In single threaded mode, don't use `async_fs` but fallback on
`std::fs` with a thin layer to mimic the async API
- file `file_asset.rs` is the async imps from `mod.rs`
- file `sync_file_asset.rs` is the same with `async_fs` APIs replaced by
`std::fs`
- which module is used depends on the `multi-threaded` feature

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-11-03 23:00:34 +00:00
papow65
708569c91e
Corrected incorrect doc comment on read_asset_bytes (#10352)
Fixes #10302 

## Solution

- Removed the incorrect comment.
2023-11-03 21:01:05 +00:00
Talin
cfcc113fb7
Additional AssetPath unit tests. (#10279)
# Objective

Additional unit test for AssetPath.
2023-10-27 03:29:25 +00:00
Niklas Eicker
bfca4384cc
Reuse and hot reload folder handles (#10210)
# Objective

- Folder handles are not shared. Loading the same folder multiple times
will result in different handles.
- Once folder handles are shared, they can no longer be manually
reloaded, so we should add support for hot-reloading them


## Solution

- Reuse folder handles based on their path
- Trigger a reload of a folder if a file contained in it (or a sub
folder) is added or removed
- This also covers adding/removing/moving sub folders containing files

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-10-26 22:19:57 +00:00
Niklas Eicker
77309ba5d8
Non-blocking load_untyped using a wrapper asset (#10198)
# Objective

- Assets v2 does not currently offer a public API to load untyped assets

## Solution

- Wrap the untyped handle in a `LoadedUntypedAsset` asset to offer a
non-blocking load for untyped assets. The user does not need to know the
actual asset type.
- Handles to `LoadedUntypedAsset` have the same path as the wrapped
asset, but their handles are shared using a label.

The user side of `load_untyped` looks like this:
```rust
use bevy::prelude::*;
use bevy_internal::asset::LoadedUntypedAsset;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, check)
        .run();
}

#[derive(Resource)]
struct UntypedAsset {
    handle: Handle<LoadedUntypedAsset>,
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    let handle = asset_server.load_untyped("branding/banner.png");
    commands.insert_resource(UntypedAsset { handle });
    commands.spawn(Camera2dBundle::default());
}

fn check(
    mut commands: Commands,
    res: Option<Res<UntypedAsset>>,
    assets: Res<Assets<LoadedUntypedAsset>>,
) {
    if let Some(untyped_asset) = res {
        if let Some(asset) = assets.get(&untyped_asset.handle) {
            commands.spawn(SpriteBundle {
                texture: asset.handle.clone().typed(),
                ..default()
            });
            commands.remove_resource::<UntypedAsset>();
        }
    }
}
```

---

## Changelog

- `load_untyped` on the asset server now returns a handle to a
`LoadedUntypedAsset` instead of an untyped handle to the asset at the
given path. The untyped handle for the given path can be retrieved from
the `LoadedUntypedAsset` once it is done loading.


## Migration Guide

Whenever possible use the typed API in order to directly get a handle to
your asset. If you do not know the type or need to use `load_untyped`
for a different reason, Bevy 0.12 introduces an additional layer of
indirection. The asset server will return a handle to a
`LoadedUntypedAsset`, which will load in the background. Once it is
loaded, the untyped handle to the asset file can be retrieved from the
`LoadedUntypedAsset`s field `handle`.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-10-26 22:14:32 +00:00
François
e5b3cc45ba
Assets: fix first hot reloading (#9804)
# Objective

- Hot reloading doesn't work the first time it is used

## Solution

- Currently, Bevy processor:
  1. Create the `imported_assets` folder
  2. Setup a watcher on it
  3. Clear empty folders, so the `imported_assets` folder is deleted
4. Recreate the `imported_assets` folder and add all the imported assets
- On a first run without an existing `imported_assets` with some
content, hot reloading won't work as step 3 breaks the file watcher
- This PR stops the empty root folder from being deleted
- Also don't setup the processor internal asset server for file
watching, freeing up a thread

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-10-26 21:32:12 +00:00
Talin
c81e2bd586
Adding AssetPath::resolve() method. (#9528)
# Objective

Fixes #9473 

## Solution

Added `resolve()` method to AssetPath. This method accepts a relative
asset path string and returns a "full" path that has been resolved
relative to the current (self) path.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-10-26 21:05:45 +00:00
François
d938275b9c
assets: use blake3 instead of md5 (#10208)
# Objective

- Replace md5 by another hasher, as suggested in
https://github.com/bevyengine/bevy/pull/8624#discussion_r1359291028
- md5 is not secure, and is slow. use something more secure and faster

## Solution

- Replace md5 by blake3


Putting this PR in the 0.12 as once it's released, changing the hash
algorithm will be a painful breaking change
2023-10-23 04:15:04 +00:00
anarelion
f9ef989def
Implement source into Display for AssetPath (#10217)
# Objective

When debugging and printing asset paths, I am not 100% if I am in the
right source or not

## Solution

Add the output of the source
2023-10-22 22:59:39 +00:00
Carter Anderson
6f27e0e35f
Add asset_processor feature and remove AssetMode::ProcessedDev (#10194)
# Objective

Users shouldn't need to change their source code between "development
workflows" and "releasing". Currently, Bevy Asset V2 has two "processed"
asset modes `Processed` (assumes assets are already processed) and
`ProcessedDev` (starts an asset processor and processes assets). This
means that the mode must be changed _in code_ when switching from "app
dev" to "release". Very suboptimal.

We have already removed "runtime opt-in" for hot-reloading. Enabling the
`file_watcher` feature _automatically_ enables file watching in code.
This means deploying a game (without hot reloading enabled) just means
calling `cargo build --release` instead of `cargo run --features
bevy/file_watcher`.

We should adopt this pattern for asset processing.

## Solution

This adds the `asset_processor` feature, which will start the
`AssetProcessor` when an `AssetPlugin` runs in `AssetMode::Processed`.

The "asset processing workflow" is now:
1. Enable `AssetMode::Processed` on `AssetPlugin`
2. When developing, run with the `asset_processor` and `file_watcher`
features
3. When releasing, build without these features.

The `AssetMode::ProcessedDev` mode has been removed.
2023-10-20 20:50:26 +00:00
Torstein Grindvik
7132404b38
Add note about asset source register order (#10186)
# Objective

I encountered a problem where I had a plugin `FooPlugin` which did

```rust
impl Plugin for FooPlugin {
    fn build(&self, app: &mut App) {
        app
           .register_asset_source(...); // more stuff after
    }
}
```

And when I tried using it, e.g.

```rust
asset_server.load("foo://data/asset.custom");
```

I got an error that `foo` was not recognized as a source.

I found that this is because asset sources must be registered _before_
`AssetPlugin` is added, and I had `FooPlugin` _after_.

## Solution

Add clarifying note about having to register sources before
`AssetPlugin` is added.

Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
2023-10-20 14:43:16 +00:00
66OJ66
4e28fa255d
Log an error when registering an AssetSource after AssetPlugin has been built (#10202)
# Objective

- Provides actionable feedback when users encounter the error in
https://github.com/bevyengine/bevy/issues/10162
- Complements https://github.com/bevyengine/bevy/pull/10186

## Solution

- Log an error when registering an AssetSource after the AssetPlugin has
been built (via DefaultPlugins). This will let users know that their
registration order needs changing

The outputted error message will look like this:
```rust
ERROR bevy_asset::server: 'AssetSourceId::Name(test)' must be registered before `AssetPlugin` (typically added as part of `DefaultPlugins`)
```

---------

Co-authored-by: 66OJ66 <hi0obxud@anonaddy.me>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-10-20 14:42:47 +00:00
François
4d286d087b
remove unused import on android (#10197)
# Objective

- Building for android has a warning
```
warning: unused import: `AssetWatcher`
 --> crates/bevy_asset/src/io/android.rs:2:51
  |
2 |     get_meta_path, AssetReader, AssetReaderError, AssetWatcher, EmptyPathStream, PathStream,
  |                                                   ^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default
```

## Solution

- Remove the import
2023-10-19 23:02:04 +00:00
Carter Anderson
02943737b2
Return an error when loading non-existent labels (#9751)
# Objective

Calling `asset_server.load("scene.gltf#SomeLabel")` will silently fail
if `SomeLabel` does not exist.

Referenced in #9714 

## Solution

We now detect this case and return an error. I also slightly refactored
`load_internal` to make the logic / dataflow much clearer.

---------

Co-authored-by: Pascal Hertleif <killercup@gmail.com>
2023-10-15 18:36:51 +00:00
Carter Anderson
49d5c6b8a3
Hot reload labeled assets whose source asset is not loaded (#9736)
# Objective

As called out in #9714, Bevy Asset V2 fails to hot-reload labeled assets
whose source asset has changed (in cases where the root asset is not
alive).

## Solution

Track alive labeled assets for a given source asset and allow hot
reloads in cases where a labeled asset is still alive.
2023-10-15 18:21:49 +00:00
François
5781806e72
only set up processed source if asset plugin is not unprocessed (#10123)
# Objective

- Since #9885, running on an iOS device crashes trying to create the
processed folder
- This only happens on real device, not on the simulator

## Solution

- Setup processed assets only if needed
2023-10-15 18:20:29 +00:00
Carter Anderson
3866b1cc19
Fix load_folder for non-default Asset Sources (#10121)
# Objective

Fixes #10120

## Solution

Assign the folder path source to loaded descendant asset paths in
`load_folder`
2023-10-15 16:57:46 +00:00
Dworv
ca37b92540
Make loading warning for no file ext more descriptive (#10119)
# Objective

Currently, the asset loader outputs 
```
2023-10-14T15:11:09.328850Z  WARN bevy_asset::asset_server: no `AssetLoader` found
```
when user forgets to add an extension to a file. This is very confusing
behaviour, it sounds like there aren't any asset loaders existing.

## Solution

Add an extra message on the end when there are no file extensions.
2023-10-14 22:54:57 +00:00
Carter Anderson
35073cf7aa
Multiple Asset Sources (#9885)
This adds support for **Multiple Asset Sources**. You can now register a
named `AssetSource`, which you can load assets from like you normally
would:

```rust
let shader: Handle<Shader> = asset_server.load("custom_source://path/to/shader.wgsl");
```

Notice that `AssetPath` now supports `some_source://` syntax. This can
now be accessed through the `asset_path.source()` accessor.

Asset source names _are not required_. If one is not specified, the
default asset source will be used:

```rust
let shader: Handle<Shader> = asset_server.load("path/to/shader.wgsl");
```

The behavior of the default asset source has not changed. Ex: the
`assets` folder is still the default.

As referenced in #9714

## Why?

**Multiple Asset Sources** enables a number of often-asked-for
scenarios:

* **Loading some assets from other locations on disk**: you could create
a `config` asset source that reads from the OS-default config folder
(not implemented in this PR)
* **Loading some assets from a remote server**: you could register a new
`remote` asset source that reads some assets from a remote http server
(not implemented in this PR)
* **Improved "Binary Embedded" Assets**: we can use this system for
"embedded-in-binary assets", which allows us to replace the old
`load_internal_asset!` approach, which couldn't support asset
processing, didn't support hot-reloading _well_, and didn't make
embedded assets accessible to the `AssetServer` (implemented in this pr)

## Adding New Asset Sources

An `AssetSource` is "just" a collection of `AssetReader`, `AssetWriter`,
and `AssetWatcher` entries. You can configure new asset sources like
this:

```rust
app.register_asset_source(
    "other",
    AssetSource::build()
        .with_reader(|| Box::new(FileAssetReader::new("other")))
    )
)
```

Note that `AssetSource` construction _must_ be repeatable, which is why
a closure is accepted.
`AssetSourceBuilder` supports `with_reader`, `with_writer`,
`with_watcher`, `with_processed_reader`, `with_processed_writer`, and
`with_processed_watcher`.

Note that the "asset source" system replaces the old "asset providers"
system.

## Processing Multiple Sources

The `AssetProcessor` now supports multiple asset sources! Processed
assets can refer to assets in other sources and everything "just works".
Each `AssetSource` defines an unprocessed and processed `AssetReader` /
`AssetWriter`.

Currently this is all or nothing for a given `AssetSource`. A given
source is either processed or it is not. Later we might want to add
support for "lazy asset processing", where an `AssetSource` (such as a
remote server) can be configured to only process assets that are
directly referenced by local assets (in order to save local disk space
and avoid doing extra work).

## A new `AssetSource`: `embedded`

One of the big features motivating **Multiple Asset Sources** was
improving our "embedded-in-binary" asset loading. To prove out the
**Multiple Asset Sources** implementation, I chose to build a new
`embedded` `AssetSource`, which replaces the old `load_interal_asset!`
system.

The old `load_internal_asset!` approach had a number of issues:

* The `AssetServer` was not aware of (or capable of loading) internal
assets.
* Because internal assets weren't visible to the `AssetServer`, they
could not be processed (or used by assets that are processed). This
would prevent things "preprocessing shaders that depend on built in Bevy
shaders", which is something we desperately need to start doing.
* Each "internal asset" needed a UUID to be defined in-code to reference
it. This was very manual and toilsome.

The new `embedded` `AssetSource` enables the following pattern:

```rust
// Called in `crates/bevy_pbr/src/render/mesh.rs`
embedded_asset!(app, "mesh.wgsl");

// later in the app
let shader: Handle<Shader> = asset_server.load("embedded://bevy_pbr/render/mesh.wgsl");
```

Notice that this always treats the crate name as the "root path", and it
trims out the `src` path for brevity. This is generally predictable, but
if you need to debug you can use the new `embedded_path!` macro to get a
`PathBuf` that matches the one used by `embedded_asset`.

You can also reference embedded assets in arbitrary assets, such as WGSL
shaders:

```rust
#import "embedded://bevy_pbr/render/mesh.wgsl"
```

This also makes `embedded` assets go through the "normal" asset
lifecycle. They are only loaded when they are actually used!

We are also discussing implicitly converting asset paths to/from shader
modules, so in the future (not in this PR) you might be able to load it
like this:

```rust
#import bevy_pbr::render::mesh::Vertex
```

Compare that to the old system!

```rust
pub const MESH_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(3252377289100772450);

load_internal_asset!(app, MESH_SHADER_HANDLE, "mesh.wgsl", Shader::from_wgsl);

// The mesh asset is the _only_ accessible via MESH_SHADER_HANDLE and _cannot_ be loaded via the AssetServer.
```

## Hot Reloading `embedded`

You can enable `embedded` hot reloading by enabling the
`embedded_watcher` cargo feature:

```
cargo run --features=embedded_watcher
```

## Improved Hot Reloading Workflow

First: the `filesystem_watcher` cargo feature has been renamed to
`file_watcher` for brevity (and to match the `FileAssetReader` naming
convention).

More importantly, hot asset reloading is no longer configured in-code by
default. If you enable any asset watcher feature (such as `file_watcher`
or `rust_source_watcher`), asset watching will be automatically enabled.

This removes the need to _also_ enable hot reloading in your app code.
That means you can replace this:

```rust
app.add_plugins(DefaultPlugins.set(AssetPlugin::default().watch_for_changes()))
```

with this:

```rust
app.add_plugins(DefaultPlugins)
```

If you want to hot reload assets in your app during development, just
run your app like this:

```
cargo run --features=file_watcher
```

This means you can use the same code for development and deployment! To
deploy an app, just don't include the watcher feature

```
cargo build --release
```

My intent is to move to this approach for pretty much all dev workflows.
In a future PR I would like to replace `AssetMode::ProcessedDev` with a
`runtime-processor` cargo feature. We could then group all common "dev"
cargo features under a single `dev` feature:

```sh
# this would enable file_watcher, embedded_watcher, runtime-processor, and more
cargo run --features=dev
```

## AssetMode

`AssetPlugin::Unprocessed`, `AssetPlugin::Processed`, and
`AssetPlugin::ProcessedDev` have been replaced with an `AssetMode` field
on `AssetPlugin`.

```rust
// before 
app.add_plugins(DefaultPlugins.set(AssetPlugin::Processed { /* fields here */ })

// after 
app.add_plugins(DefaultPlugins.set(AssetPlugin { mode: AssetMode::Processed, ..default() })
```

This aligns `AssetPlugin` with our other struct-like plugins. The old
"source" and "destination" `AssetProvider` fields in the enum variants
have been replaced by the "asset source" system. You no longer need to
configure the AssetPlugin to "point" to custom asset providers.

## AssetServerMode

To improve the implementation of **Multiple Asset Sources**,
`AssetServer` was made aware of whether or not it is using "processed"
or "unprocessed" assets. You can check that like this:

```rust
if asset_server.mode() == AssetServerMode::Processed {
    /* do something */
}
```

Note that this refactor should also prepare the way for building "one to
many processed output files", as it makes the server aware of whether it
is loading from processed or unprocessed sources. Meaning we can store
and read processed and unprocessed assets differently!

## AssetPath can now refer to folders

The "file only" restriction has been removed from `AssetPath`. The
`AssetServer::load_folder` API now accepts an `AssetPath` instead of a
`Path`, meaning you can load folders from other asset sources!

## Improved AssetPath Parsing

AssetPath parsing was reworked to support sources, improve error
messages, and to enable parsing with a single pass over the string.
`AssetPath::new` was replaced by `AssetPath::parse` and
`AssetPath::try_parse`.

## AssetWatcher broken out from AssetReader

`AssetReader` is no longer responsible for constructing `AssetWatcher`.
This has been moved to `AssetSourceBuilder`.


## Duplicate Event Debouncing

Asset V2 already debounced duplicate filesystem events, but this was
_input_ events. Multiple input event types can produce the same _output_
`AssetSourceEvent`. Now that we have `embedded_watcher`, which does
expensive file io on events, it made sense to debounce output events
too, so I added that! This will also benefit the AssetProcessor by
preventing integrity checks for duplicate events (and helps keep the
noise down in trace logs).

## Next Steps

* **Port Built-in Shaders**: Currently the primary (and essentially
only) user of `load_interal_asset` in Bevy's source code is "built-in
shaders". I chose not to do that in this PR for a few reasons:
1. We need to add the ability to pass shader defs in to shaders via meta
files. Some shaders (such as MESH_VIEW_TYPES) need to pass shader def
values in that are defined in code.
2. We need to revisit the current shader module naming system. I think
we _probably_ want to imply modules from source structure (at least by
default). Ideally in a way that can losslessly convert asset paths
to/from shader modules (to enable the asset system to resolve modules
using the asset server).
  3. I want to keep this change set minimal / get this merged first.
* **Deprecate `load_internal_asset`**: we can't do that until we do (1)
and (2)
* **Relative Asset Paths**: This PR significantly increases the need for
relative asset paths (which was already pretty high). Currently when
loading dependencies, it is assumed to be an absolute path, which means
if in an `AssetLoader` you call `context.load("some/path/image.png")` it
will assume that is the "default" asset source, _even if the current
asset is in a different asset source_. This will cause breakage for
AssetLoaders that are not designed to add the current source to whatever
paths are being used. AssetLoaders should generally not need to be aware
of the name of their current asset source, or need to think about the
"current asset source" generally. We should build apis that support
relative asset paths and then encourage using relative paths as much as
possible (both via api design and docs). Relative paths are also
important because they will allow developers to move folders around
(even across providers) without reprocessing, provided there is no path
breakage.
2023-10-13 23:17:32 +00:00
Zachary Harrold
dd46fd3aee
Removed anyhow (#10003)
# Objective

- Fixes #8140

## Solution

- Added Explicit Error Typing for `AssetLoader` and `AssetSaver`, which
were the last instances of `anyhow` in use across Bevy.

---

## Changelog

- Added an associated type `Error` to `AssetLoader` and `AssetSaver` for
use with the `load` and `save` methods respectively.
- Changed `ErasedAssetLoader` and `ErasedAssetSaver` `load` and `save`
methods to use `Box<dyn Error + Send + Sync + 'static>` to allow for
arbitrary `Error` types from the non-erased trait variants. Note the
strict requirements match the pre-existing requirements around
`anyhow::Error`.

## Migration Guide

- `anyhow` is no longer exported by `bevy_asset`; Add it to your own
project (if required).
- `AssetLoader` and `AssetSaver` have an associated type `Error`; Define
an appropriate error type (e.g., using `thiserror`), or use a pre-made
error type (e.g., `anyhow::Error`). Note that using `anyhow::Error` is a
drop-in replacement.
- `AssetLoaderError` has been removed; Define a new error type, or use
an alternative (e.g., `anyhow::Error`)
- All the first-party `AssetLoader`'s and `AssetSaver`'s now return
relevant (and narrow) error types instead of a single ambiguous type;
Match over the specific error type, or encapsulate (`Box<dyn>`,
`thiserror`, `anyhow`, etc.)

## Notes

A simpler PR to resolve this issue would simply define a Bevy `Error`
type defined as `Box<dyn std::error::Error + Send + Sync + 'static>`,
but I think this type of error handling should be discouraged when
possible. Since only 2 traits required the use of `anyhow`, it isn't a
substantive body of work to solidify these error types, and remove
`anyhow` entirely. End users are still encouraged to use `anyhow` if
that is their preferred error handling style. Arguably, adding the
`Error` associated type gives more freedom to end-users to decide
whether they want more or less explicit error handling (`anyhow` vs
`thiserror`).

As an aside, I didn't perform any testing on Android or WASM. CI passed
locally, but there may be mistakes for those platforms I missed.
2023-10-06 07:20:13 +00:00
Mike
7c5b324484
Ignore ambiguous components or resources (#9895)
# Objective

- Fixes #9884
- Add API for ignoring ambiguities on certain resource or components.

## Solution

- Add a `IgnoreSchedulingAmbiguitiy` resource to the world which holds
the `ComponentIds` to be ignored
- Filter out ambiguities with those component id's.

## Changelog

- add `allow_ambiguous_component` and `allow_ambiguous_resource` apis
for ignoring ambiguities

---------

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-10-04 02:34:28 +00:00
Bruce Mitchener
9a798aa100
Allow clippy::type_complexity in more places. (#9796)
# Objective

- See fewer warnings when running `cargo clippy` locally.

## Solution

- allow `clippy::type_complexity` in more places, which also signals to
users they should do the same.
2023-10-02 21:55:16 +00:00
Rob Parrett
7063c86ed4
Fix some typos (#9934)
# Objective

To celebrate the turning of the seasons, I took a small walk through the
codebase guided by the "[code spell
checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)"
VS Code extension and fixed a few typos.
2023-09-26 19:46:24 +00:00
Pixelstorm
503b861e3a
Allow using async_io::block_on in bevy_tasks (#9626)
# Objective

Fixes #9625

## Solution

Adds `async-io` as an optional dependency of `bevy_tasks`. When enabled,
this causes calls to `futures_lite::future::block_on` to be replaced
with calls to `async_io::block_on`.

---

## Changelog

- Added a new `async-io` feature to `bevy_tasks`. When enabled, this
causes `bevy_tasks` to use `async-io`'s implemention of `block_on`
instead of `futures-lite`'s implementation. You should enable this if
you use `async-io` in your application.
2023-09-25 19:59:50 +00:00
Joseph
d5d355ae1f
Fix the clippy::explicit_iter_loop lint (#9834)
# Objective

Replace instances of

```rust
for x in collection.iter{_mut}() {
```

with

```rust
for x in &{mut} collection {
```

This also changes CI to no longer suppress this lint. Note that since
this lint only shows up when using clippy in pedantic mode, it was
probably unnecessary to suppress this lint in the first place.
2023-09-19 03:35:22 +00:00
Carter Anderson
5fb3eb5cb9
Manual "Reflect Value" AssetPath impl to fix dynamic linking (#9752)
# Objective

Fix #9747

## Solution

Linkers don't like what we're doing with CowArc (I'm guessing it has
something to do with `?Sized`). Weirdly the `Reflect` derive on
`AssetPath` doesn't fail, despite `CowArc` not implementing `Reflect`.

To resolve this, we manually implement "reflect value" for
`AssetPath<'static>`. It sadly cannot use `impl_reflect_value` because
that macro doesn't support static lifetimes.

---------

Co-authored-by: Martin Dickopp <martin@zero-based.org>
2023-09-13 18:29:19 +00:00
François
72b8f47780
don't ignore some EventKind::Modify (#9767)
# Objective

- File modification don't trigger hot reload on macOS 

## Solution

-
[`EventKind::Modify`](https://docs.rs/notify/latest/notify/event/enum.EventKind.html#variant.Modify)
can have several reasons
-
[`ModifyKind::Any`](https://docs.rs/notify/latest/notify/event/enum.ModifyKind.html)
was used to react to change events, and later ModifyKind::Name for file
name change. It left other variants of change ignored (`Data`,
`Metadata`, `Other`)
- move the modification handling after the rename so that it handles all
other variants
2023-09-13 05:45:39 +00:00
Zhixing Zhang
8fa500d016
Asset v2: Asset path serialization fix (#9756)
# Objective

- Silence `Failed to send DropEvent for StrongHandle "SendError(..)"`
errors when `StrongHandle` were dropped during application shutdown.
- Re-export `BoxedFuture` considering that it's used everywhere in
bevy_asset
- Fixed an issue introduced by #9729. 
  ```
Asset 'final_gather.rgen' encountered an error in
dust_render::shader::spirv::SpirvLoader: Failed to deserialize asset
meta: SpannedError { code: InvalidValueForType { expected: "string
AssetPath", found: "a sequence" }, position: Position { line: 9, col: 24
} }
  ```
Basically, for processed assets with dependencies, bevy will serialize
the metafile as follows:
  ```
  (
    meta_format_version: "1.0",
    processed_info: Some((
hash: (203, 239, 108, 156, 180, 23, 157, 217, 159, 36, 158, 193, 185,
253, 242, 156),
full_hash: (77, 58, 30, 200, 21, 180, 221, 133, 151, 83, 247, 47, 193,
70, 228, 97),
        process_dependencies: [
            (
full_hash: (56, 46, 55, 118, 3, 6, 213, 250, 124, 26, 153, 87, 15, 85,
4, 89),
                path: ("standard.glsl"), # <<---------- See here
            ),
        ],
    )),
    asset: Load(
        loader: "dust_render::shader::spirv::SpirvLoader",
        settings: (),
    ),
  )
  ```
`AssetPath` gets serialized as `("standard.glsl")` which was then
deserialized as a sequence instead of our `AssetPath`.

## Solution

- Serialize `AssetPath` directly as a string instead. The above metafile
would be serialized as follows:
 ```
  (
    meta_format_version: "1.0",
    processed_info: Some((
hash: (203, 239, 108, 156, 180, 23, 157, 217, 159, 36, 158, 193, 185,
253, 242, 156),
full_hash: (77, 58, 30, 200, 21, 180, 221, 133, 151, 83, 247, 47, 193,
70, 228, 97),
        process_dependencies: [
            (
full_hash: (56, 46, 55, 118, 3, 6, 213, 250, 124, 26, 153, 87, 15, 85,
4, 89),
path: "standard.glsl", # <<------- No longer a tuple struct
            ),
        ],
    )),
    asset: Load(
        loader: "dust_render::shader::spirv::SpirvLoader",
        settings: (),
    ),
  )
  ```

---
2023-09-13 05:43:01 +00:00
Carter Anderson
0c44de7626
Increase iteration count for asset tests (#9737)
This needs to be much higher to avoid failures in CI. I don't love the
"loop until" test methodology generally, but this is testing internal
state and making this event driven would change the nature of the test.
2023-09-10 21:37:33 +00:00
Carter Anderson
17edf4f7c7
Copy on Write AssetPaths (#9729)
# Objective

The `AssetServer` and `AssetProcessor` do a lot of `AssetPath` cloning
(across many threads). To store the path on the handle, to store paths
in dependency lists, to pass an owned path to the offloaded thread, to
pass a path to the LoadContext, etc , etc. Cloning multiple string
allocations multiple times like this will add up. It is worth optimizing
this.

Referenced in #9714 

## Solution

Added a new `CowArc<T>` type to `bevy_util`, which behaves a lot like
`Cow<T>`, but the Owned variant is an `Arc<T>`. Use this in place of
`Cow<str>` and `Cow<Path>` on `AssetPath`.

---

## Changelog

- `AssetPath` now internally uses `CowArc`, making clone operations much
cheaper
- `AssetPath` now serializes as `AssetPath("some_path.extension#Label")`
instead of as `AssetPath { path: "some_path.extension", label:
Some("Label) }`


## Migration Guide

```rust
// Old
AssetPath::new("logo.png", None);

// New
AssetPath::new("logo.png");

// Old
AssetPath::new("scene.gltf", Some("Mesh0");

// New
AssetPath::new("scene.gltf").with_label("Mesh0");
```

`AssetPath` now serializes as `AssetPath("some_path.extension#Label")`
instead of as `AssetPath { path: "some_path.extension", label:
Some("Label) }`

---------

Co-authored-by: Pascal Hertleif <killercup@gmail.com>
2023-09-09 23:15:10 +00:00
Ame :]
1980ac88f1
Fix some warnings (#9724)
# Objective

- Fix these warnings 

```rust
warning: unused doc comment
  --> /bevy/crates/bevy_pbr/src/light.rs:62:13
   |
62 |             /// Luminous power in lumens
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63 |             intensity: 800.0, // Roughly a 60W non-halogen incandescent bulb
   |             ---------------- rustdoc does not generate documentation for expression fields
   |
   = help: use `//` for a plain comment
   = note: `#[warn(unused_doc_comments)]` on by default
```

```rust
warning: `&` without an explicit lifetime name cannot be used here
  --> /bevy/crates/bevy_asset/src/lib.rs:89:32
   |
89 |     const DEFAULT_FILE_SOURCE: &str = "assets";
   |                                ^
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
   = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default
help: use the `'static` lifetime
   |
89 |     const DEFAULT_FILE_SOURCE: &'static str = "assets";
   |   
```
2023-09-08 21:49:03 +00:00
François
c8f61c3963
create imported asset directory if needed (#9716)
# Objective

- Related to #9715 
- Example `asset_processing` logs the following error:
```
thread 'IO Task Pool (1)' panicked at 'Failed to initialize asset processor log. This cannot be recovered. Try restarting. If that doesn't work, try deleting processed asset folder. No such file or directory (os error 2)', crates/bevy_asset/src/processor/mod.rs:867:25
```

## Solution

- Create the log directory if needed

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-09-07 20:47:42 +00:00
Carter Anderson
5eb292dc10
Bevy Asset V2 (#8624)
# Bevy Asset V2 Proposal

## Why Does Bevy Need A New Asset System?

Asset pipelines are a central part of the gamedev process. Bevy's
current asset system is missing a number of features that make it
non-viable for many classes of gamedev. After plenty of discussions and
[a long community feedback
period](https://github.com/bevyengine/bevy/discussions/3972), we've
identified a number missing features:

* **Asset Preprocessing**: it should be possible to "preprocess" /
"compile" / "crunch" assets at "development time" rather than when the
game starts up. This enables offloading expensive work from deployed
apps, faster asset loading, less runtime memory usage, etc.
* **Per-Asset Loader Settings**: Individual assets cannot define their
own loaders that override the defaults. Additionally, they cannot
provide per-asset settings to their loaders. This is a huge limitation,
as many asset types don't provide all information necessary for Bevy
_inside_ the asset. For example, a raw PNG image says nothing about how
it should be sampled (ex: linear vs nearest).
* **Asset `.meta` files**: assets should have configuration files stored
adjacent to the asset in question, which allows the user to configure
asset-type-specific settings. These settings should be accessible during
the pre-processing phase. Modifying a `.meta` file should trigger a
re-processing / re-load of the asset. It should be possible to configure
asset loaders from the meta file.
* **Processed Asset Hot Reloading**: Changes to processed assets (or
their dependencies) should result in re-processing them and re-loading
the results in live Bevy Apps.
* **Asset Dependency Tracking**: The current bevy_asset has no good way
to wait for asset dependencies to load. It punts this as an exercise for
consumers of the loader apis, which is unreasonable and error prone.
There should be easy, ergonomic ways to wait for assets to load and
block some logic on an asset's entire dependency tree loading.
* **Runtime Asset Loading**: it should be (optionally) possible to load
arbitrary assets dynamically at runtime. This necessitates being able to
deploy and run the asset server alongside Bevy Apps on _all platforms_.
For example, we should be able to invoke the shader compiler at runtime,
stream scenes from sources like the internet, etc. To keep deployed
binaries (and startup times) small, the runtime asset server
configuration should be configurable with different settings compared to
the "pre processor asset server".
* **Multiple Backends**: It should be possible to load assets from
arbitrary sources (filesystems, the internet, remote asset serves, etc).
* **Asset Packing**: It should be possible to deploy assets in
compressed "packs", which makes it easier and more efficient to
distribute assets with Bevy Apps.
* **Asset Handoff**: It should be possible to hold a "live" asset
handle, which correlates to runtime data, without actually holding the
asset in memory. Ex: it must be possible to hold a reference to a GPU
mesh generated from a "mesh asset" without keeping the mesh data in CPU
memory
* **Per-Platform Processed Assets**: Different platforms and app
distributions have different capabilities and requirements. Some
platforms need lower asset resolutions or different asset formats to
operate within the hardware constraints of the platform. It should be
possible to define per-platform asset processing profiles. And it should
be possible to deploy only the assets required for a given platform.

These features have architectural implications that are significant
enough to require a full rewrite. The current Bevy Asset implementation
got us this far, but it can take us no farther. This PR defines a brand
new asset system that implements most of these features, while laying
the foundations for the remaining features to be built.

## Bevy Asset V2

Here is a quick overview of the features introduced in this PR.
* **Asset Preprocessing**: Preprocess assets at development time into
more efficient (and configurable) representations
* **Dependency Aware**: Dependencies required to process an asset are
tracked. If an asset's processed dependency changes, it will be
reprocessed
* **Hot Reprocessing/Reloading**: detect changes to asset source files,
reprocess them if they have changed, and then hot-reload them in Bevy
Apps.
* **Only Process Changes**: Assets are only re-processed when their
source file (or meta file) has changed. This uses hashing and timestamps
to avoid processing assets that haven't changed.
* **Transactional and Reliable**: Uses write-ahead logging (a technique
commonly used by databases) to recover from crashes / forced-exits.
Whenever possible it avoids full-reprocessing / only uncompleted
transactions will be reprocessed. When the processor is running in
parallel with a Bevy App, processor asset writes block Bevy App asset
reads. Reading metadata + asset bytes is guaranteed to be transactional
/ correctly paired.
* **Portable / Run anywhere / Database-free**: The processor does not
rely on an in-memory database (although it uses some database techniques
for reliability). This is important because pretty much all in-memory
databases have unsupported platforms or build complications.
* **Configure Processor Defaults Per File Type**: You can say "use this
processor for all files of this type".
* **Custom Processors**: The `Processor` trait is flexible and
unopinionated. It can be implemented by downstream plugins.
* **LoadAndSave Processors**: Most asset processing scenarios can be
expressed as "run AssetLoader A, save the results using AssetSaver X,
and then load the result using AssetLoader B". For example, load this
png image using `PngImageLoader`, which produces an `Image` asset and
then save it using `CompressedImageSaver` (which also produces an
`Image` asset, but in a compressed format), which takes an `Image` asset
as input. This means if you have an `AssetLoader` for an asset, you are
already half way there! It also means that you can share AssetSavers
across multiple loaders. Because `CompressedImageSaver` accepts Bevy's
generic Image asset as input, it means you can also use it with some
future `JpegImageLoader`.
* **Loader and Saver Settings**: Asset Loaders and Savers can now define
their own settings types, which are passed in as input when an asset is
loaded / saved. Each asset can define its own settings.
* **Asset `.meta` files**: configure asset loaders, their settings,
enable/disable processing, and configure processor settings
* **Runtime Asset Dependency Tracking** Runtime asset dependencies (ex:
if an asset contains a `Handle<Image>`) are tracked by the asset server.
An event is emitted when an asset and all of its dependencies have been
loaded
* **Unprocessed Asset Loading**: Assets do not require preprocessing.
They can be loaded directly. A processed asset is just a "normal" asset
with some extra metadata. Asset Loaders don't need to know or care about
whether or not an asset was processed.
* **Async Asset IO**: Asset readers/writers use async non-blocking
interfaces. Note that because Rust doesn't yet support async traits,
there is a bit of manual Boxing / Future boilerplate. This will
hopefully be removed in the near future when Rust gets async traits.
* **Pluggable Asset Readers and Writers**: Arbitrary asset source
readers/writers are supported, both by the processor and the asset
server.
* **Better Asset Handles**
* **Single Arc Tree**: Asset Handles now use a single arc tree that
represents the lifetime of the asset. This makes their implementation
simpler, more efficient, and allows us to cheaply attach metadata to
handles. Ex: the AssetPath of a handle is now directly accessible on the
handle itself!
* **Const Typed Handles**: typed handles can be constructed in a const
context. No more weird "const untyped converted to typed at runtime"
patterns!
* **Handles and Ids are Smaller / Faster To Hash / Compare**: Typed
`Handle<T>` is now much smaller in memory and `AssetId<T>` is even
smaller.
* **Weak Handle Usage Reduction**: In general Handles are now considered
to be "strong". Bevy features that previously used "weak `Handle<T>`"
have been ported to `AssetId<T>`, which makes it statically clear that
the features do not hold strong handles (while retaining strong type
information). Currently Handle::Weak still exists, but it is very
possible that we can remove that entirely.
* **Efficient / Dense Asset Ids**: Assets now have efficient dense
runtime asset ids, which means we can avoid expensive hash lookups.
Assets are stored in Vecs instead of HashMaps. There are now typed and
untyped ids, which means we no longer need to store dynamic type
information in the ID for typed handles. "AssetPathId" (which was a
nightmare from a performance and correctness standpoint) has been
entirely removed in favor of dense ids (which are retrieved for a path
on load)
* **Direct Asset Loading, with Dependency Tracking**: Assets that are
defined at runtime can still have their dependencies tracked by the
Asset Server (ex: if you create a material at runtime, you can still
wait for its textures to load). This is accomplished via the (currently
optional) "asset dependency visitor" trait. This system can also be used
to define a set of assets to load, then wait for those assets to load.
* **Async folder loading**: Folder loading also uses this system and
immediately returns a handle to the LoadedFolder asset, which means
folder loading no longer blocks on directory traversals.
* **Improved Loader Interface**: Loaders now have a specific "top level
asset type", which makes returning the top-level asset simpler and
statically typed.
* **Basic Image Settings and Processing**: Image assets can now be
processed into the gpu-friendly Basic Universal format. The ImageLoader
now has a setting to define what format the image should be loaded as.
Note that this is just a minimal MVP ... plenty of additional work to do
here. To demo this, enable the `basis-universal` feature and turn on
asset processing.
* **Simpler Audio Play / AudioSink API**: Asset handle providers are
cloneable, which means the Audio resource can mint its own handles. This
means you can now do `let sink_handle = audio.play(music)` instead of
`let sink_handle = audio_sinks.get_handle(audio.play(music))`. Note that
this might still be replaced by
https://github.com/bevyengine/bevy/pull/8424.
**Removed Handle Casting From Engine Features**: Ex: FontAtlases no
longer use casting between handle types

## Using The New Asset System

### Normal Unprocessed Asset Loading

By default the `AssetPlugin` does not use processing. It behaves pretty
much the same way as the old system.

If you are defining a custom asset, first derive `Asset`:

```rust
#[derive(Asset)]
struct Thing {
    value: String,
}
```

Initialize the asset:
```rust
app.init_asset:<Thing>()
```

Implement a new `AssetLoader` for it:

```rust
#[derive(Default)]
struct ThingLoader;

#[derive(Serialize, Deserialize, Default)]
pub struct ThingSettings {
    some_setting: bool,
}

impl AssetLoader for ThingLoader {
    type Asset = Thing;
    type Settings = ThingSettings;

    fn load<'a>(
        &'a self,
        reader: &'a mut Reader,
        settings: &'a ThingSettings,
        load_context: &'a mut LoadContext,
    ) -> BoxedFuture<'a, Result<Thing, anyhow::Error>> {
        Box::pin(async move {
            let mut bytes = Vec::new();
            reader.read_to_end(&mut bytes).await?;
            // convert bytes to value somehow
            Ok(Thing {
                value 
            })
        })
    }

    fn extensions(&self) -> &[&str] {
        &["thing"]
    }
}
```

Note that this interface will get much cleaner once Rust gets support
for async traits. `Reader` is an async futures_io::AsyncRead. You can
stream bytes as they come in or read them all into a `Vec<u8>`,
depending on the context. You can use `let handle =
load_context.load(path)` to kick off a dependency load, retrieve a
handle, and register the dependency for the asset.

Then just register the loader in your Bevy app:

```rust
app.init_asset_loader::<ThingLoader>()
```

Now just add your `Thing` asset files into the `assets` folder and load
them like this:

```rust
fn system(asset_server: Res<AssetServer>) {
    let handle = Handle<Thing> = asset_server.load("cool.thing");
}
```

You can check load states directly via the asset server:

```rust
if asset_server.load_state(&handle) == LoadState::Loaded { }
```

You can also listen for events:

```rust
fn system(mut events: EventReader<AssetEvent<Thing>>, handle: Res<SomeThingHandle>) {
    for event in events.iter() {
        if event.is_loaded_with_dependencies(&handle) {
        }
    }
}
```

Note the new `AssetEvent::LoadedWithDependencies`, which only fires when
the asset is loaded _and_ all dependencies (and their dependencies) have
loaded.

Unlike the old asset system, for a given asset path all `Handle<T>`
values point to the same underlying Arc. This means Handles can cheaply
hold more asset information, such as the AssetPath:

```rust
// prints the AssetPath of the handle
info!("{:?}", handle.path())
```

### Processed Assets

Asset processing can be enabled via the `AssetPlugin`. When developing
Bevy Apps with processed assets, do this:

```rust
app.add_plugins(DefaultPlugins.set(AssetPlugin::processed_dev()))
```

This runs the `AssetProcessor` in the background with hot-reloading. It
reads assets from the `assets` folder, processes them, and writes them
to the `.imported_assets` folder. Asset loads in the Bevy App will wait
for a processed version of the asset to become available. If an asset in
the `assets` folder changes, it will be reprocessed and hot-reloaded in
the Bevy App.

When deploying processed Bevy apps, do this:

```rust
app.add_plugins(DefaultPlugins.set(AssetPlugin::processed()))
```

This does not run the `AssetProcessor` in the background. It behaves
like `AssetPlugin::unprocessed()`, but reads assets from
`.imported_assets`.

When the `AssetProcessor` is running, it will populate sibling `.meta`
files for assets in the `assets` folder. Meta files for assets that do
not have a processor configured look like this:

```rust
(
    meta_format_version: "1.0",
    asset: Load(
        loader: "bevy_render::texture::image_loader::ImageLoader",
        settings: (
            format: FromExtension,
        ),
    ),
)
```

This is metadata for an image asset. For example, if you have
`assets/my_sprite.png`, this could be the metadata stored at
`assets/my_sprite.png.meta`. Meta files are totally optional. If no
metadata exists, the default settings will be used.

In short, this file says "load this asset with the ImageLoader and use
the file extension to determine the image type". This type of meta file
is supported in all AssetPlugin modes. If in `Unprocessed` mode, the
asset (with the meta settings) will be loaded directly. If in
`ProcessedDev` mode, the asset file will be copied directly to the
`.imported_assets` folder. The meta will also be copied directly to the
`.imported_assets` folder, but with one addition:

```rust
(
    meta_format_version: "1.0",
    processed_info: Some((
        hash: 12415480888597742505,
        full_hash: 14344495437905856884,
        process_dependencies: [],
    )),
    asset: Load(
        loader: "bevy_render::texture::image_loader::ImageLoader",
        settings: (
            format: FromExtension,
        ),
    ),
)
```

`processed_info` contains `hash` (a direct hash of the asset and meta
bytes), `full_hash` (a hash of `hash` and the hashes of all
`process_dependencies`), and `process_dependencies` (the `path` and
`full_hash` of every process_dependency). A "process dependency" is an
asset dependency that is _directly_ used when processing the asset.
Images do not have process dependencies, so this is empty.

When the processor is enabled, you can use the `Process` metadata
config:

```rust
(
    meta_format_version: "1.0",
    asset: Process(
        processor: "bevy_asset::processor::process::LoadAndSave<bevy_render::texture::image_loader::ImageLoader, bevy_render::texture::compressed_image_saver::CompressedImageSaver>",
        settings: (
            loader_settings: (
                format: FromExtension,
            ),
            saver_settings: (
                generate_mipmaps: true,
            ),
        ),
    ),
)
```

This configures the asset to use the `LoadAndSave` processor, which runs
an AssetLoader and feeds the result into an AssetSaver (which saves the
given Asset and defines a loader to load it with). (for terseness
LoadAndSave will likely get a shorter/friendlier type name when [Stable
Type Paths](#7184) lands). `LoadAndSave` is likely to be the most common
processor type, but arbitrary processors are supported.

`CompressedImageSaver` saves an `Image` in the Basis Universal format
and configures the ImageLoader to load it as basis universal. The
`AssetProcessor` will read this meta, run it through the LoadAndSave
processor, and write the basis-universal version of the image to
`.imported_assets`. The final metadata will look like this:

```rust
(
    meta_format_version: "1.0",
    processed_info: Some((
        hash: 905599590923828066,
        full_hash: 9948823010183819117,
        process_dependencies: [],
    )),
    asset: Load(
        loader: "bevy_render::texture::image_loader::ImageLoader",
        settings: (
            format: Format(Basis),
        ),
    ),
)
```

To try basis-universal processing out in Bevy examples, (for example
`sprite.rs`), change `add_plugins(DefaultPlugins)` to
`add_plugins(DefaultPlugins.set(AssetPlugin::processed_dev()))` and run
with the `basis-universal` feature enabled: `cargo run
--features=basis-universal --example sprite`.

To create a custom processor, there are two main paths:
1. Use the `LoadAndSave` processor with an existing `AssetLoader`.
Implement the `AssetSaver` trait, register the processor using
`asset_processor.register_processor::<LoadAndSave<ImageLoader,
CompressedImageSaver>>(image_saver.into())`.
2. Implement the `Process` trait directly and register it using:
`asset_processor.register_processor(thing_processor)`.

You can configure default processors for file extensions like this:

```rust
asset_processor.set_default_processor::<ThingProcessor>("thing")
```

There is one more metadata type to be aware of:

```rust
(
    meta_format_version: "1.0",
    asset: Ignore,
)
```

This will ignore the asset during processing / prevent it from being
written to `.imported_assets`.

The AssetProcessor stores a transaction log at `.imported_assets/log`
and uses it to gracefully recover from unexpected stops. This means you
can force-quit the processor (and Bevy Apps running the processor in
parallel) at arbitrary times!

`.imported_assets` is "local state". It should _not_ be checked into
source control. It should also be considered "read only". In practice,
you _can_ modify processed assets and processed metadata if you really
need to test something. But those modifications will not be represented
in the hashes of the assets, so the processed state will be "out of
sync" with the source assets. The processor _will not_ fix this for you.
Either revert the change after you have tested it, or delete the
processed files so they can be re-populated.

## Open Questions

There are a number of open questions to be discussed. We should decide
if they need to be addressed in this PR and if so, how we will address
them:

### Implied Dependencies vs Dependency Enumeration

There are currently two ways to populate asset dependencies:
* **Implied via AssetLoaders**: if an AssetLoader loads an asset (and
retrieves a handle), a dependency is added to the list.
* **Explicit via the optional Asset::visit_dependencies**: if
`server.load_asset(my_asset)` is called, it will call
`my_asset.visit_dependencies`, which will grab dependencies that have
been manually defined for the asset via the Asset trait impl (which can
be derived).

This means that defining explicit dependencies is optional for "loaded
assets". And the list of dependencies is always accurate because loaders
can only produce Handles if they register dependencies. If an asset was
loaded with an AssetLoader, it only uses the implied dependencies. If an
asset was created at runtime and added with
`asset_server.load_asset(MyAsset)`, it will use
`Asset::visit_dependencies`.

However this can create a behavior mismatch between loaded assets and
equivalent "created at runtime" assets if `Assets::visit_dependencies`
doesn't exactly match the dependencies produced by the AssetLoader. This
behavior mismatch can be resolved by completely removing "implied loader
dependencies" and requiring `Asset::visit_dependencies` to supply
dependency data. But this creates two problems:
* It makes defining loaded assets harder and more error prone: Devs must
remember to manually annotate asset dependencies with `#[dependency]`
when deriving `Asset`. For more complicated assets (such as scenes), the
derive likely wouldn't be sufficient and a manual `visit_dependencies`
impl would be required.
* Removes the ability to immediately kick off dependency loads: When
AssetLoaders retrieve a Handle, they also immediately kick off an asset
load for the handle, which means it can start loading in parallel
_before_ the asset finishes loading. For large assets, this could be
significant. (although this could be mitigated for processed assets if
we store dependencies in the processed meta file and load them ahead of
time)

### Eager ProcessorDev Asset Loading

I made a controversial call in the interest of fast startup times ("time
to first pixel") for the "processor dev mode configuration". When
initializing the AssetProcessor, current processed versions of unchanged
assets are yielded immediately, even if their dependencies haven't been
checked yet for reprocessing. This means that
non-current-state-of-filesystem-but-previously-valid assets might be
returned to the App first, then hot-reloaded if/when their dependencies
change and the asset is reprocessed.

Is this behavior desirable? There is largely one alternative: do not
yield an asset from the processor to the app until all of its
dependencies have been checked for changes. In some common cases (load
dependency has not changed since last run) this will increase startup
time. The main question is "by how much" and is that slower startup time
worth it in the interest of only yielding assets that are true to the
current state of the filesystem. Should this be configurable? I'm
starting to think we should only yield an asset after its (historical)
dependencies have been checked for changes + processed as necessary, but
I'm curious what you all think.

### Paths Are Currently The Only Canonical ID / Do We Want Asset UUIDs?

In this implementation AssetPaths are the only canonical asset
identifier (just like the previous Bevy Asset system and Godot). Moving
assets will result in re-scans (and currently reprocessing, although
reprocessing can easily be avoided with some changes). Asset
renames/moves will break code and assets that rely on specific paths,
unless those paths are fixed up.

Do we want / need "stable asset uuids"? Introducing them is very
possible:
1. Generate a UUID and include it in .meta files
2. Support UUID in AssetPath
3. Generate "asset indices" which are loaded on startup and map UUIDs to
paths.
4 (maybe). Consider only supporting UUIDs for processed assets so we can
generate quick-to-load indices instead of scanning meta files.

The main "pro" is that assets referencing UUIDs don't need to be
migrated when a path changes. The main "con" is that UUIDs cannot be
"lazily resolved" like paths. They need a full view of all assets to
answer the question "does this UUID exist". Which means UUIDs require
the AssetProcessor to fully finish startup scans before saying an asset
doesnt exist. And they essentially require asset pre-processing to use
in apps, because scanning all asset metadata files at runtime to resolve
a UUID is not viable for medium-to-large apps. It really requires a
pre-generated UUID index, which must be loaded before querying for
assets.

I personally think this should be investigated in a separate PR. Paths
aren't going anywhere ... _everyone_ uses filesystems (and
filesystem-like apis) to manage their asset source files. I consider
them permanent canonical asset information. Additionally, they behave
well for both processed and unprocessed asset modes. Given that Bevy is
supporting both, this feels like the right canonical ID to start with.
UUIDS (and maybe even other indexed-identifier types) can be added later
as necessary.

### Folder / File Naming Conventions

All asset processing config currently lives in the `.imported_assets`
folder. The processor transaction log is in `.imported_assets/log`.
Processed assets are added to `.imported_assets/Default`, which will
make migrating to processed asset profiles (ex: a
`.imported_assets/Mobile` profile) a non-breaking change. It also allows
us to create top-level files like `.imported_assets/log` without it
being interpreted as an asset. Meta files currently have a `.meta`
suffix. Do we like these names and conventions?

### Should the `AssetPlugin::processed_dev` configuration enable
`watch_for_changes` automatically?

Currently it does (which I think makes sense), but it does make it the
only configuration that enables watch_for_changes by default.

### Discuss on_loaded High Level Interface:

This PR includes a very rough "proof of concept" `on_loaded` system
adapter that uses the `LoadedWithDependencies` event in combination with
`asset_server.load_asset` dependency tracking to support this pattern

```rust
fn main() {
    App::new()
        .init_asset::<MyAssets>()
        .add_systems(Update, on_loaded(create_array_texture))
        .run();
}

#[derive(Asset, Clone)]
struct MyAssets {
    #[dependency]
    picture_of_my_cat: Handle<Image>,
    #[dependency]
    picture_of_my_other_cat: Handle<Image>,
}

impl FromWorld for ArrayTexture {
    fn from_world(world: &mut World) -> Self {
        picture_of_my_cat: server.load("meow.png"),
        picture_of_my_other_cat: server.load("meeeeeeeow.png"),
    }
}

fn spawn_cat(In(my_assets): In<MyAssets>, mut commands: Commands) {
    commands.spawn(SpriteBundle {
        texture: my_assets.picture_of_my_cat.clone(),  
        ..default()
    });
    
    commands.spawn(SpriteBundle {
        texture: my_assets.picture_of_my_other_cat.clone(),  
        ..default()
    });
}

```

The implementation is _very_ rough. And it is currently unsafe because
`bevy_ecs` doesn't expose some internals to do this safely from inside
`bevy_asset`. There are plenty of unanswered questions like:
* "do we add a Loadable" derive? (effectively automate the FromWorld
implementation above)
* Should `MyAssets` even be an Asset? (largely implemented this way
because it elegantly builds on `server.load_asset(MyAsset { .. })`
dependency tracking).

We should think hard about what our ideal API looks like (and if this is
a pattern we want to support). Not necessarily something we need to
solve in this PR. The current `on_loaded` impl should probably be
removed from this PR before merging.

## Clarifying Questions

### What about Assets as Entities?

This Bevy Asset V2 proposal implementation initially stored Assets as
ECS Entities. Instead of `AssetId<T>` + the `Assets<T>` resource it used
`Entity` as the asset id and Asset values were just ECS components.
There are plenty of compelling reasons to do this:
1. Easier to inline assets in Bevy Scenes (as they are "just" normal
entities + components)
2. More flexible queries: use the power of the ECS to filter assets (ex:
`Query<Mesh, With<Tree>>`).
3. Extensible. Users can add arbitrary component data to assets.
4. Things like "component visualization tools" work out of the box to
visualize asset data.

However Assets as Entities has a ton of caveats right now:
* We need to be able to allocate entity ids without a direct World
reference (aka rework id allocator in Entities ... i worked around this
in my prototypes by just pre allocating big chunks of entities)
* We want asset change events in addition to ECS change tracking ... how
do we populate them when mutations can come from anywhere? Do we use
Changed queries? This would require iterating over the change data for
all assets every frame. Is this acceptable or should we implement a new
"event based" component change detection option?
* Reconciling manually created assets with asset-system managed assets
has some nuance (ex: are they "loaded" / do they also have that
component metadata?)
* "how do we handle "static" / default entity handles" (ties in to the
Entity Indices discussion:
https://github.com/bevyengine/bevy/discussions/8319). This is necessary
for things like "built in" assets and default handles in things like
SpriteBundle.
* Storing asset information as a component makes it easy to "invalidate"
asset state by removing the component (or forcing modifications).
Ideally we have ways to lock this down (some combination of Rust type
privacy and ECS validation)

In practice, how we store and identify assets is a reasonably
superficial change (porting off of Assets as Entities and implementing
dedicated storage + ids took less than a day). So once we sort out the
remaining challenges the flip should be straightforward. Additionally, I
do still have "Assets as Entities" in my commit history, so we can reuse
that work. I personally think "assets as entities" is a good endgame,
but it also doesn't provide _significant_ value at the moment and it
certainly isn't ready yet with the current state of things.

### Why not Distill?

[Distill](https://github.com/amethyst/distill) is a high quality fully
featured asset system built in Rust. It is very natural to ask "why not
just use Distill?".

It is also worth calling out that for awhile, [we planned on adopting
Distill / I signed off on
it](https://github.com/bevyengine/bevy/issues/708).

However I think Bevy has a number of constraints that make Distill
adoption suboptimal:
* **Architectural Simplicity:**
* Distill's processor requires an in-memory database (lmdb) and RPC
networked API (using Cap'n Proto). Each of these introduces API
complexity that increases maintenance burden and "code grokability".
Ignoring tests, documentation, and examples, Distill has 24,237 lines of
Rust code (including generated code for RPC + database interactions). If
you ignore generated code, it has 11,499 lines.
* Bevy builds the AssetProcessor and AssetServer using pluggable
AssetReader/AssetWriter Rust traits with simple io interfaces. They do
not necessitate databases or RPC interfaces (although Readers/Writers
could use them if that is desired). Bevy Asset V2 (at the time of
writing this PR) is 5,384 lines of Rust code (ignoring tests,
documentation, and examples). Grain of salt: Distill does have more
features currently (ex: Asset Packing, GUIDS, remote-out-of-process
asset processor). I do plan to implement these features in Bevy Asset V2
and I personally highly doubt they will meaningfully close the 6115
lines-of-code gap.
* This complexity gap (which while illustrated by lines of code, is much
bigger than just that) is noteworthy to me. Bevy should be hackable and
there are pillars of Distill that are very hard to understand and
extend. This is a matter of opinion (and Bevy Asset V2 also has
complicated areas), but I think Bevy Asset V2 is much more approachable
for the average developer.
* Necessary disclaimer: counting lines of code is an extremely rough
complexity metric. Read the code and form your own opinions.
* **Optional Asset Processing:** Not all Bevy Apps (or Bevy App
developers) need / want asset preprocessing. Processing increases the
complexity of the development environment by introducing things like
meta files, imported asset storage, running processors in the
background, waiting for processing to finish, etc. Distill _requires_
preprocessing to work. With Bevy Asset V2 processing is fully opt-in.
The AssetServer isn't directly aware of asset processors at all.
AssetLoaders only care about converting bytes to runtime Assets ... they
don't know or care if the bytes were pre-processed or not. Processing is
"elegantly" (forgive my self-congratulatory phrasing) layered on top and
builds on the existing Asset system primitives.
* **Direct Filesystem Access to Processed Asset State:** Distill stores
processed assets in a database. This makes debugging / inspecting the
processed outputs harder (either requires special tooling to query the
database or they need to be "deployed" to be inspected). Bevy Asset V2,
on the other hand, stores processed assets in the filesystem (by default
... this is configurable). This makes interacting with the processed
state more natural. Note that both Godot and Unity's new asset system
store processed assets in the filesystem.
* **Portability**: Because Distill's processor uses lmdb and RPC
networking, it cannot be run on certain platforms (ex: lmdb is a
non-rust dependency that cannot run on the web, some platforms don't
support running network servers). Bevy should be able to process assets
everywhere (ex: run the Bevy Editor on the web, compile + process
shaders on mobile, etc). Distill does partially mitigate this problem by
supporting "streaming" assets via the RPC protocol, but this is not a
full solve from my perspective. And Bevy Asset V2 can (in theory) also
stream assets (without requiring RPC, although this isn't implemented
yet)

Note that I _do_ still think Distill would be a solid asset system for
Bevy. But I think the approach in this PR is a better solve for Bevy's
specific "asset system requirements".

### Doesn't async-fs just shim requests to "sync" `std::fs`? What is the
point?

"True async file io" has limited / spotty platform support. async-fs
(and the rust async ecosystem generally ... ex Tokio) currently use
async wrappers over std::fs that offload blocking requests to separate
threads. This may feel unsatisfying, but it _does_ still provide value
because it prevents our task pools from blocking on file system
operations (which would prevent progress when there are many tasks to
do, but all threads in a pool are currently blocking on file system
ops).

Additionally, using async APIs for our AssetReaders and AssetWriters
also provides value because we can later add support for "true async
file io" for platforms that support it. _And_ we can implement other
"true async io" asset backends (such as networked asset io).

## Draft TODO

- [x] Fill in missing filesystem event APIs: file removed event (which
is expressed as dangling RenameFrom events in some cases), file/folder
renamed event
- [x] Assets without loaders are not moved to the processed folder. This
breaks things like referenced `.bin` files for GLTFs. This should be
configurable per-non-asset-type.
- [x] Initial implementation of Reflect and FromReflect for Handle. The
"deserialization" parity bar is low here as this only worked with static
UUIDs in the old impl ... this is a non-trivial problem. Either we add a
Handle::AssetPath variant that gets "upgraded" to a strong handle on
scene load or we use a separate AssetRef type for Bevy scenes (which is
converted to a runtime Handle on load). This deserves its own discussion
in a different pr.
- [x] Populate read_asset_bytes hash when run by the processor (a bit of
a special case .. when run by the processor the processed meta will
contain the hash so we don't need to compute it on the spot, but we
don't want/need to read the meta when run by the main AssetServer)
- [x] Delay hot reloading: currently filesystem events are handled
immediately, which creates timing issues in some cases. For example hot
reloading images can sometimes break because the image isn't finished
writing. We should add a delay, likely similar to the [implementation in
this PR](https://github.com/bevyengine/bevy/pull/8503).
- [x] Port old platform-specific AssetIo implementations to the new
AssetReader interface (currently missing Android and web)
- [x] Resolve on_loaded unsafety (either by removing the API entirely or
removing the unsafe)
- [x]  Runtime loader setting overrides
- [x] Remove remaining unwraps that should be error-handled. There are
number of TODOs here
- [x] Pretty AssetPath Display impl
- [x] Document more APIs
- [x] Resolve spurious "reloading because it has changed" events (to
repro run load_gltf with `processed_dev()`)
- [x] load_dependency hot reloading currently only works for processed
assets. If processing is disabled, load_dependency changes are not hot
reloaded.
- [x] Replace AssetInfo dependency load/fail counters with
`loading_dependencies: HashSet<UntypedAssetId>` to prevent reloads from
(potentially) breaking counters. Storing this will also enable
"dependency reloaded" events (see [Next Steps](#next-steps))
- [x] Re-add filesystem watcher cargo feature gate (currently it is not
optional)
- [ ] Migration Guide
- [ ] Changelog

## Followup TODO

- [ ] Replace "eager unchanged processed asset loading" behavior with
"don't returned unchanged processed asset until dependencies have been
checked".
- [ ] Add true `Ignore` AssetAction that does not copy the asset to the
imported_assets folder.
- [ ] Finish "live asset unloading" (ex: free up CPU asset memory after
uploading an image to the GPU), rethink RenderAssets, and port renderer
features. The `Assets` collection uses `Option<T>` for asset storage to
support its removal. (1) the Option might not actually be necessary ...
might be able to just remove from the collection entirely (2) need to
finalize removal apis
- [ ] Try replacing the "channel based" asset id recycling with
something a bit more efficient (ex: we might be able to use raw atomic
ints with some cleverness)
- [ ] Consider adding UUIDs to processed assets (scoped just to helping
identify moved assets ... not exposed to load queries ... see [Next
Steps](#next-steps))
- [ ] Store "last modified" source asset and meta timestamps in
processed meta files to enable skipping expensive hashing when the file
wasn't changed
- [ ] Fix "slow loop" handle drop fix 
- [ ] Migrate to TypeName
- [x] Handle "loader preregistration". See #9429

## Next Steps

* **Configurable per-type defaults for AssetMeta**: It should be
possible to add configuration like "all png image meta should default to
using nearest sampling" (currently this hard-coded per-loader/processor
Settings::default() impls). Also see the "Folder Meta" bullet point.
* **Avoid Reprocessing on Asset Renames / Moves**: See the "canonical
asset ids" discussion in [Open Questions](#open-questions) and the
relevant bullet point in [Draft TODO](#draft-todo). Even without
canonical ids, folder renames could avoid reprocessing in some cases.
* **Multiple Asset Sources**: Expand AssetPath to support "asset source
names" and support multiple AssetReaders in the asset server (ex:
`webserver://some_path/image.png` backed by an Http webserver
AssetReader). The "default" asset reader would use normal
`some_path/image.png` paths. Ideally this works in combination with
multiple AssetWatchers for hot-reloading
* **Stable Type Names**: this pr removes the TypeUuid requirement from
assets in favor of `std::any::type_name`. This makes defining assets
easier (no need to generate a new uuid / use weird proc macro syntax).
It also makes reading meta files easier (because things have "friendly
names"). We also use type names for components in scene files. If they
are good enough for components, they are good enough for assets. And
consistency across Bevy pillars is desirable. However,
`std::any::type_name` is not guaranteed to be stable (although in
practice it is). We've developed a [stable type
path](https://github.com/bevyengine/bevy/pull/7184) to resolve this,
which should be adopted when it is ready.
* **Command Line Interface**: It should be possible to run the asset
processor in a separate process from the command line. This will also
require building a network-server-backed AssetReader to communicate
between the app and the processor. We've been planning to build a "bevy
cli" for awhile. This seems like a good excuse to build it.
* **Asset Packing**: This is largely an additive feature, so it made
sense to me to punt this until we've laid the foundations in this PR.
* **Per-Platform Processed Assets**: It should be possible to generate
assets for multiple platforms by supporting multiple "processor
profiles" per asset (ex: compress with format X on PC and Y on iOS). I
think there should probably be arbitrary "profiles" (which can be
separate from actual platforms), which are then assigned to a given
platform when generating the final asset distribution for that platform.
Ex: maybe devs want a "Mobile" profile that is shared between iOS and
Android. Or a "LowEnd" profile shared between web and mobile.
* **Versioning and Migrations**: Assets, Loaders, Savers, and Processors
need to have versions to determine if their schema is valid. If an asset
/ loader version is incompatible with the current version expected at
runtime, the processor should be able to migrate them. I think we should
try using Bevy Reflect for this, as it would allow us to load the old
version as a dynamic Reflect type without actually having the old Rust
type. It would also allow us to define "patches" to migrate between
versions (Bevy Reflect devs are currently working on patching). The
`.meta` file already has its own format version. Migrating that to new
versions should also be possible.
* **Real Copy-on-write AssetPaths**: Rust's actual Cow (clone-on-write
type) currently used by AssetPath can still result in String clones that
aren't actually necessary (cloning an Owned Cow clones the contents).
Bevy's asset system requires cloning AssetPaths in a number of places,
which result in actual clones of the internal Strings. This is not
efficient. AssetPath internals should be reworked to exhibit truer
cow-like-behavior that reduces String clones to the absolute minimum.
* **Consider processor-less processing**: In theory the AssetServer
could run processors "inline" even if the background AssetProcessor is
disabled. If we decide this is actually desirable, we could add this.
But I don't think its a priority in the short or medium term.
* **Pre-emptive dependency loading**: We could encode dependencies in
processed meta files, which could then be used by the Asset Server to
kick of dependency loads as early as possible (prior to starting the
actual asset load). Is this desirable? How much time would this save in
practice?
* **Optimize Processor With UntypedAssetIds**: The processor exclusively
uses AssetPath to identify assets currently. It might be possible to
swap these out for UntypedAssetIds in some places, which are smaller /
cheaper to hash and compare.
* **One to Many Asset Processing**: An asset source file that produces
many assets currently must be processed into a single "processed" asset
source. If labeled assets can be written separately they can each have
their own configured savers _and_ they could be loaded more granularly.
Definitely worth exploring!
* **Automatically Track "Runtime-only" Asset Dependencies**: Right now,
tracking "created at runtime" asset dependencies requires adding them
via `asset_server.load_asset(StandardMaterial::default())`. I think with
some cleverness we could also do this for
`materials.add(StandardMaterial::default())`, making tracking work
"everywhere". There are challenges here relating to change detection /
ensuring the server is made aware of dependency changes. This could be
expensive in some cases.
* **"Dependency Changed" events**: Some assets have runtime artifacts
that need to be re-generated when one of their dependencies change (ex:
regenerate a material's bind group when a Texture needs to change). We
are generating the dependency graph so we can definitely produce these
events. Buuuuut generating these events will have a cost / they could be
high frequency for some assets, so we might want this to be opt-in for
specific cases.
* **Investigate Storing More Information In Handles**: Handles can now
store arbitrary information, which makes it cheaper and easier to
access. How much should we move into them? Canonical asset load states
(via atomics)? (`handle.is_loaded()` would be very cool). Should we
store the entire asset and remove the `Assets<T>` collection?
(`Arc<RwLock<Option<Image>>>`?)
* **Support processing and loading files without extensions**: This is a
pretty arbitrary restriction and could be supported with very minimal
changes.
* **Folder Meta**: It would be nice if we could define per folder
processor configuration defaults (likely in a `.meta` or `.folder_meta`
file). Things like "default to linear filtering for all Images in this
folder".
* **Replace async_broadcast with event-listener?** This might be
approximately drop-in for some uses and it feels more light weight
* **Support Running the AssetProcessor on the Web**: Most of the hard
work is done here, but there are some easy straggling TODOs (make the
transaction log an interface instead of a direct file writer so we can
write a web storage backend, implement an AssetReader/AssetWriter that
reads/writes to something like LocalStorage).
* **Consider identifying and preventing circular dependencies**: This is
especially important for "processor dependencies", as processing will
silently never finish in these cases.
* **Built-in/Inlined Asset Hot Reloading**: This PR regresses
"built-in/inlined" asset hot reloading (previously provided by the
DebugAssetServer). I'm intentionally punting this because I think it can
be cleanly implemented with "multiple asset sources" by registering a
"debug asset source" (ex: `debug://bevy_pbr/src/render/pbr.wgsl` asset
paths) in combination with an AssetWatcher for that asset source and
support for "manually loading pats with asset bytes instead of
AssetReaders". The old DebugAssetServer was quite nasty and I'd love to
avoid that hackery going forward.
* **Investigate ways to remove double-parsing meta files**: Parsing meta
files currently involves parsing once with "minimal" versions of the
meta file to extract the type name of the loader/processor config, then
parsing again to parse the "full" meta. This is suboptimal. We should be
able to define custom deserializers that (1) assume the loader/processor
type name comes first (2) dynamically looks up the loader/processor
registrations to deserialize settings in-line (similar to components in
the bevy scene format). Another alternative: deserialize as dynamic
Reflect objects and then convert.
* **More runtime loading configuration**: Support using the Handle type
as a hint to select an asset loader (instead of relying on AssetPath
extensions)
* **More high level Processor trait implementations**: For example, it
might be worth adding support for arbitrary chains of "asset transforms"
that modify an in-memory asset representation between loading and
saving. (ex: load a Mesh, run a `subdivide_mesh` transform, followed by
a `flip_normals` transform, then save the mesh to an efficient
compressed format).
* **Bevy Scene Handle Deserialization**: (see the relevant [Draft TODO
item](#draft-todo) for context)
* **Explore High Level Load Interfaces**: See [this
discussion](#discuss-on_loaded-high-level-interface) for one prototype.
* **Asset Streaming**: It would be great if we could stream Assets (ex:
stream a long video file piece by piece)
* **ID Exchanging**: In this PR Asset Handles/AssetIds are bigger than
they need to be because they have a Uuid enum variant. If we implement
an "id exchanging" system that trades Uuids for "efficient runtime ids",
we can cut down on the size of AssetIds, making them more efficient.
This has some open design questions, such as how to spawn entities with
"default" handle values (as these wouldn't have access to the exchange
api in the current system).
* **Asset Path Fixup Tooling**: Assets that inline asset paths inside
them will break when an asset moves. The asset system provides the
functionality to detect when paths break. We should build a framework
that enables formats to define "path migrations". This is especially
important for scene files. For editor-generated files, we should also
consider using UUIDs (see other bullet point) to avoid the need to
migrate in these cases.

---------

Co-authored-by: BeastLe9enD <beastle9end@outlook.de>
Co-authored-by: Mike <mike.hsu@gmail.com>
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2023-09-07 02:07:27 +00:00
Emi
3527288342
Fixing some doc comments (#9646)
# Objective
I've been collecting some mistakes in the documentation and fixed them

---------

Co-authored-by: Emi <emanuel.boehm@gmail.com>
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2023-08-31 19:05:49 +00:00
Alex Kocharin
94c67afa4b
Fix panic when using .load_folder() with absolute paths (#9490)
Fixes https://github.com/bevyengine/bevy/issues/9458.

On case-insensitive filesystems (Windows, Mac, NTFS mounted in Linux,
etc.), a path can be represented in a multiple ways:

 - `c:\users\user\rust\assets\hello\world`
 - `c:/users/user/rust/assets/hello/world`
 - `C:\USERS\USER\rust\assets\hello\world`

If user specifies a path variant that doesn't match asset folder path
bevy calculates, `path.strip_prefix()` will fail, as demonstrated below:

```rs
dbg!(Path::new("c:/foo/bar/baz").strip_prefix("c:/foo"));
// Ok("bar/baz")

dbg!(Path::new("c:/FOO/bar/baz").strip_prefix("c:/foo"));
// StripPrefixError(())
```

This commit rewrites the code in question in a way that prefix stripping
is no longer necessary.

I've tested with the following paths on my computer:

```rs
let res = asset_server.load_folder("C:\\Users\\user\\rust\\assets\\foo\\bar");
dbg!(res);

let res = asset_server.load_folder("c:\\users\\user\\rust\\assets\\foo\\bar");
dbg!(res);

let res = asset_server.load_folder("C:/Users/user/rust/assets/foo/bar");
dbg!(res);
```
2023-08-28 17:23:44 +00:00
Rob Parrett
a788e31ad5
Fix CI for Rust 1.72 (#9562)
# Objective

[Rust 1.72.0](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html) is
now stable.

# Notes

- `let-else` formatting has arrived!
- I chose to allow `explicit_iter_loop` due to
https://github.com/rust-lang/rust-clippy/issues/11074.
  
We didn't hit any of the false positives that prevent compilation, but
fixing this did produce a lot of the "symbol soup" mentioned, e.g. `for
image in &mut *image_events {`.
  
  Happy to undo this if there's consensus the other way.

---------

Co-authored-by: François <mockersf@gmail.com>
2023-08-25 12:34:24 +00:00
robtfm
8a8d43d224
fix asset loader preregistration for multiple assets (#9453)
# Objective

fix #9452

when multiple assets are queued to a preregistered loader, only one gets
unblocked when the real loader is registered.

## Solution

i thought async_channel receivers worked like broadcast channels, but in
fact the notification is only received by a single receiver, so only a
single waiting asset is unblocked. close the sender instead so that all
blocked receivers are unblocked.
2023-08-17 20:56:41 +00:00
robtfm
b30ff2ab76
allow asset loader pre-registration (#9429)
# Objective

- When loading gltf files during app creation (for example using a
FromWorld impl and adding that as a resource), no loader was found.
- As the gltf loader can load compressed formats, it needs to know what
the GPU supports so it's not available at app creation time.

## Solution

alternative to #9426

- add functionality to preregister the loader. loading assets with
matching extensions will block until a real loader is registered.
- preregister "gltf" and "glb".
- prereigster image formats.

the way this is set up, if a set of extensions are all registered with a
single preregistration call, then later a loader is added that matches
some of the extensions, assets using the remaining extensions will then
fail. i think that should work well for image formats that we don't know
are supported until later.
2023-08-14 21:27:51 +00:00
Sélène Amanita
cbe13f3aa5
Improve Mesh documentation (#9061)
# Objective

This PR continues https://github.com/bevyengine/bevy/pull/8885

It aims to improve the `Mesh` documentation in the following ways:
- Put everything at the "top level" instead of the "impl".
- Explain better what is a Mesh, how it can be created, and that it can
be edited.
- Explain it can be used with a `Material`, and mention
`StandardMaterial`, `PbrBundle`, `ColorMaterial`, and
`ColorMesh2dBundle` since those cover most cases
- Mention the glTF/Bevy vocabulary discrepancy for "Mesh"
- Add an image for the example
- Various nitpicky modifications

## Note

- The image I added is 90.3ko which I think is small enough?
- Since rustdoc doesn't allow cross-reference not in dependencies of a
subcrate [yet](https://github.com/rust-lang/rust/issues/74481), I have a
lot of backtick references that are not links :(
- Since rustdoc doesn't allow linking to code in the crate (?) I put
link to github directly.
- Since rustdoc doesn't allow embed images in doc
[yet](https://github.com/rust-lang/rust/issues/32104), maybe
[soon](https://github.com/rust-lang/rfcs/pull/3397), I had to put only a
link to the image. I don't think it's worth adding
[embed_doc_image](https://docs.rs/embed-doc-image/latest/embed_doc_image/)
as a dependency for this.
2023-07-31 18:55:42 +00:00
Tristan Guichaoua
a30da0001e
impl From<&AssetPath> for HandleId (#9132)
# Objective

In
[`AssetLoader::load()`](https://docs.rs/bevy/0.11.0/bevy/asset/trait.AssetLoader.html#tymethod.load),
I have an
[`AssetPath`](https://docs.rs/bevy/0.11.0/bevy/asset/struct.AssetPath.html)
to a dependency asset.
I get a handle to this dependency asset using
[`LoadContext::get_handle()`](https://docs.rs/bevy/0.11.0/bevy/asset/struct.LoadContext.html#method.get_handle)
passing the `AssetPath`. But I also need to pass this `AssetPath` to
[`LoadedAsset::with_dependency()`](https://docs.rs/bevy/0.11.0/bevy/asset/struct.LoadedAsset.html#method.with_dependency)
later.


The current solution for this problem is either use `clone()`, but
`AssetPath` may contains owned data.
```rust
let dependency_path: AssetPath = _;
let dependency = load_context.get_handle(dependency_path.clone());
// ...
load_context.set_default_asset(LoadedAsset::new(my_asset).with_dependency(dependency_path));
```

Or to use `AssetPathId::from(&path)` which is a bit verbose.
```rust
let dependency_path: AssetPath = _;
let dependency = load_context.get_handle(AssetPathId::from(&dependency_path));
// ...
load_context.set_default_asset(LoadedAsset::new(my_asset).with_dependency(dependency_path));
```

Ideal solution (introduced by this PR) is to pass a reference to
`get_handle()`.
```rust
let dependency_path: AssetPath = _;
let dependency = load_context.get_handle(&dependency_path);
// ...
load_context.set_default_asset(LoadedAsset::new(my_asset).with_dependency(dependency_path));
```

## Solution

Implement `From<&AssetPath>` for `HandleId`

---

## Changelog

- Added: `HandleId` can be build from a reference to `AssetPath`.
2023-07-15 21:32:17 +00:00
Tristan Guichaoua
30d897a8bf
fix clippy::default_constructed_unit_structs and trybuild errors (#9144)
# Objective

With Rust `1.71.0` ([released a few minutes
ago](https://github.com/rust-lang/rust/releases/tag/1.71.0)), clippy
introduced a new lint
([`default_constructed_unit_structs`](https://rust-lang.github.io/rust-clippy/master/index.html#/default_constructed_unit_structs))
wich prevent calling `default()` on unit structs (e.g.
`PhantomData::default()`).

## Solution

Apply the lint suggestion.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-07-13 22:23:04 +00:00
Tristan Guichaoua
cd0a642fa1
doc(asset): fix asset trait example (#9105)
# Objective

Fix the example code for the `Asset` trait.

## Solution

Add `TypePath` trait on `CustomAsset`.
Add a static check.
2023-07-11 21:24:43 +00:00
Gino Valente
aeeb20ec4c
bevy_reflect: FromReflect Ergonomics Implementation (#6056)
# Objective

**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**

---

Resolves #4597

Full details and motivation can be found in the RFC, but here's a brief
summary.

`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).

This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.

It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.

So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.

The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.

## Solution

Automatically derive `FromReflect` when deriving `Reflect`.

Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.

```rust
#[derive(Reflect)]
struct Foo;

#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;

fn test<T: FromReflect>(value: T) {}

test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```

#### `ReflectFromReflect`

This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.

<details>
<summary><h4>Improved Deserialization</h4></summary>

> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.

And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.

`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.

`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.

```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?;

let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;

// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry);
let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?;

let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```

</details>

---

## Changelog

* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**

## Migration Guide

* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.

  ```rust
  // OLD
  #[derive(Reflect, FromReflect)]
  struct Foo;
  
  // NEW
  #[derive(Reflect)]
  struct Foo;
  ```

If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.

  ```rust
  // OLD
  #[derive(Reflect)]
  struct Foo;
  
  impl FromReflect for Foo {/* ... */}
  
  // NEW
  #[derive(Reflect)]
  #[reflect(from_reflect = false)]
  struct Foo;
  
  impl FromReflect for Foo {/* ... */}
  ```

<details>
<summary><h4>Removed Migrations</h4></summary>

> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.

* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).

  ```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(&registry);
  let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?;
  
  // OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
  
  // NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
  ```

Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:

  ```rust
  // OLD
  let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
  
  // NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(&registry);
  ```

</details>

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
robtfm
10f5c92068
improve shader import model (#5703)
# Objective

operate on naga IR directly to improve handling of shader modules.
- give codespan reporting into imported modules
- allow glsl to be used from wgsl and vice-versa

the ultimate objective is to make it possible to 
- provide user hooks for core shader functions (to modify light
behaviour within the standard pbr pipeline, for example)
- make automatic binding slot allocation possible

but ... since this is already big, adds some value and (i think) is at
feature parity with the existing code, i wanted to push this now.

## Solution

i made a crate called naga_oil (https://github.com/robtfm/naga_oil -
unpublished for now, could be part of bevy) which manages modules by
- building each module independantly to naga IR
- creating "header" files for each supported language, which are used to
build dependent modules/shaders
- make final shaders by combining the shader IR with the IR for imported
modules

then integrated this into bevy, replacing some of the existing shader
processing stuff. also reworked examples to reflect this.

## Migration Guide

shaders that don't use `#import` directives should work without changes.

the most notable user-facing difference is that imported
functions/variables/etc need to be qualified at point of use, and
there's no "leakage" of visible stuff into your shader scope from the
imports of your imports, so if you used things imported by your imports,
you now need to import them directly and qualify them.

the current strategy of including/'spreading' `mesh_vertex_output`
directly into a struct doesn't work any more, so these need to be
modified as per the examples (e.g. color_material.wgsl, or many others).
mesh data is assumed to be in bindgroup 2 by default, if mesh data is
bound into bindgroup 1 instead then the shader def `MESH_BINDGROUP_1`
needs to be added to the pipeline shader_defs.
2023-06-27 00:29:22 +00:00
Edgar Geier
f18f28874a
Allow tuples and single plugins in add_plugins, deprecate add_plugin (#8097)
# Objective

- Better consistency with `add_systems`.
- Deprecating `add_plugin` in favor of a more powerful `add_plugins`.
- Allow passing `Plugin` to `add_plugins`.
- Allow passing tuples to `add_plugins`.

## Solution

- `App::add_plugins` now takes an `impl Plugins` parameter.
- `App::add_plugin` is deprecated.
- `Plugins` is a new sealed trait that is only implemented for `Plugin`,
`PluginGroup` and tuples over `Plugins`.
- All examples, benchmarks and tests are changed to use `add_plugins`,
using tuples where appropriate.

---

## Changelog

### Changed

- `App::add_plugins` now accepts all types that implement `Plugins`,
which is implemented for:
  - Types that implement `Plugin`.
  - Types that implement `PluginGroup`.
  - Tuples (up to 16 elements) over types that implement `Plugins`.
- Deprecated `App::add_plugin` in favor of `App::add_plugins`.

## Migration Guide

- Replace `app.add_plugin(plugin)` calls with `app.add_plugins(plugin)`.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-21 20:51:03 +00:00
Nicola Papale
0294bb191d
Move AppTypeRegistry to bevy_ecs (#8901)
# Objective

- Use `AppTypeRegistry` on API defined in `bevy_ecs`
(https://github.com/bevyengine/bevy/pull/8895#discussion_r1234748418)

A lot of the API on `Reflect` depends on a registry. When it comes to
the ECS. We should use `AppTypeRegistry` in the general case.

This is however impossible in `bevy_ecs`, since `AppTypeRegistry` is
defined in `bevy_app`.

## Solution

- Move `AppTypeRegistry` resource definition from `bevy_app` to
`bevy_ecs`
- Still add the resource in the `App` plugin, since bevy_ecs itself
doesn't know of plugins

Note that `bevy_ecs` is a dependency of `bevy_app`, so nothing
revolutionary happens.

## Alternative

- Define the API as a trait in `bevy_app` over `bevy_ecs`. (though this
prevents us from using bevy_ecs internals)
- Do not rely on `AppTypeRegistry` for the API in question, requring
users to extract themselves the resource and pass it to the API methods.

---

## Changelog

- Moved `AppTypeRegistry` resource definition from `bevy_app` to
`bevy_ecs`

## Migration Guide

- If you were **not** using a `prelude::*` to import `AppTypeRegistry`,
you should update your imports:

```diff
- use bevy::app::AppTypeRegistry;
+ use bevy::ecs::reflect::AppTypeRegistry
```
2023-06-21 17:25:01 +00:00
Niklas Eicker
f4fec7b83d
Bump hashbrown to 0.14 (#8904)
# Objective

- Keep hashbrown dependency up to date

## Solution

- Bump hashbrown to version `0.14`

This supersedes #8823
2023-06-21 13:04:44 +00:00
Niklas Eicker
96b9b6c8ad
Add missing inline documentation for android code (#8893)
# Objective

- Document android code that is currently causing clippy warnings due to
not being documented

## Solution

- Document the two previously undocumented items
2023-06-19 22:49:05 +00:00
Raffaele Ragni
7fc6db32ce
Add FromReflect where Reflect is used (#8776)
# Objective

Discovered that PointLight did not implement FromReflect. Adding
FromReflect where Reflect is used. I overreached and applied this rule
everywhere there was a Reflect without a FromReflect, except from where
the compiler wouldn't allow me.

Based from question: https://github.com/bevyengine/bevy/discussions/8774

## Solution

- Adding FromReflect where Reflect was already derived

## Notes

First PR I do in this ecosystem, so not sure if this is the usual
approach, that is, to touch many files at once.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-06-19 16:18:17 +00:00
CatThingy
89cbc78d3d
Require #[derive(Event)] on all Events (#7086)
# Objective

Be consistent with `Resource`s and `Components` and have `Event` types
be more self-documenting.
Although not susceptible to accidentally using a function instead of a
value due to `Event`s only being initialized by their type, much of the
same reasoning for removing the blanket impl on `Resource` also applies
here.

* Not immediately obvious if a type is intended to be an event
* Prevent invisible conflicts if the same third-party or primitive types
are used as events
* Allows for further extensions (e.g. opt-in warning for missed events)

## Solution

Remove the blanket impl for the `Event` trait. Add a derive macro for
it.

---

## Changelog

- `Event` is no longer implemented for all applicable types. Add the
`#[derive(Event)]` macro for events.

## Migration Guide

* Add the `#[derive(Event)]` macro for events. Third-party types used as
events should be wrapped in a newtype.
2023-06-06 14:44:32 +00:00
Michael Johnson
3507b21dce
Allow systems using Diagnostics to run in parallel (#8677)
# Objective

I was trying to add some `Diagnostics` to have a better break down of
performance but I noticed that the current implementation uses a
`ResMut` which forces the functions to all run sequentially whereas
before they could run in parallel. This created too great a performance
penalty to be usable.

## Solution

This PR reworks how the diagnostics work with a couple of breaking
changes. The idea is to change how `Diagnostics` works by changing it to
a `SystemParam`. This allows us to hold a `Deferred` buffer of
measurements that can be applied later, avoiding the need for multiple
mutable references to the hashmap. This means we can run systems that
write diagnostic measurements in parallel.

Firstly, we rename the old `Diagnostics` to `DiagnosticsStore`. This
clears up the original name for the new interface while allowing us to
preserve more closely the original API.

Then we create a new `Diagnostics` struct which implements `SystemParam`
and contains a deferred `SystemBuffer`. This can be used very similar to
the old `Diagnostics` for writing new measurements.

```rust
fn system(diagnostics: ResMut<Diagnostics>) { diagnostics.new_measurement(ID, || 10.0)}
// changes to
fn system(mut diagnostics: Diagnostics) { diagnostics.new_measurement(ID, || 10.0)}
``` 
For reading the diagnostics, the user needs to change from `Diagnostics`
to `DiagnosticsStore` but otherwise the function calls are the same.

Finally, we add a new method to the `App` for registering diagnostics.
This replaces the old method of creating a startup system and adding it
manually.

Testing it, this PR does indeed allow Diagnostic systems to be run in
parallel.

## Changelog

- Change `Diagnostics` to implement `SystemParam` which allows
diagnostic systems to run in parallel.

## Migration Guide

- Register `Diagnostic`'s using the new
`app.register_diagnostic(Diagnostic::new(DIAGNOSTIC_ID,
"diagnostic_name", 10));`
- In systems for writing new measurements, change `mut diagnostics:
ResMut<Diagnostics>` to `mut diagnostics: Diagnostics` to allow the
systems to run in parallel.
- In systems for reading measurements, change `diagnostics:
Res<Diagnostics>` to `diagnostics: Res<DiagnosticsStore>`.
2023-06-05 20:51:22 +00:00
radiish
1efc762924
reflect: stable type path v2 (#7184)
# Objective

- Introduce a stable alternative to
[`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html).
- Rewrite of #5805 with heavy inspiration in design.
- On the path to #5830.
- Part of solving #3327.


## Solution

- Add a `TypePath` trait for static stable type path/name information.
- Add a `TypePath` derive macro.
- Add a `impl_type_path` macro for implementing internal and foreign
types in `bevy_reflect`.

---

## Changelog

- Added `TypePath` trait.
- Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`.
- Added a `TypePath` derive macro.
- Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on
internal and foreign types in `bevy_reflect`.
- Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to
`(Non)GenericTypedCell<T>` which allows us to be generic over both
`TypeInfo` and `TypePath`.
- `TypePath` is now a supertrait of `Asset`, `Material` and
`Material2d`.
- `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be
specified.
- `impl_reflect_value` needs to either specify path starting with a
double colon (`::core::option::Option`) or an `in my_crate::foo`
declaration.
- Added `bevy_reflect_derive::ReflectTypePath`.
- Most uses of `Ident` in `bevy_reflect_derive` changed to use
`ReflectTypePath`.

## Migration Guide

- Implementors of `Asset`, `Material` and `Material2d` now also need to
derive `TypePath`.
- Manual implementors of `Reflect` will need to implement the new
`get_type_path` method.

## Open Questions
- [x] ~This PR currently does not migrate any usages of
`std::any::type_name` to use `bevy_reflect::TypePath` to ease the review
process. Should it?~ Migration will be left to a follow-up PR.
- [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to
satisfy new bounds, mostly when deriving `TypeUuid`. Should we make
`TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in
favour of
`TypePath`?](2afbd85532 (r961067892))
2023-06-05 20:31:20 +00:00
François
ebac7e8268
update ahash and hashbrown (#8623)
# Objective

- Update `ahash` and `hashbrown`
- Alternative to #5700 and #7420

## Solution

- Update the dependencies

This is a breaking change because we were creating two fixed hashers
with
[`AHasher::new_with_keys`](https://docs.rs/ahash/0.7.6/ahash/struct.AHasher.html#method.new_with_keys),
which was a method that existed only for testing purpose and has been
removed from public.

I replaced it with
[`RandomState::with_seeds`](https://docs.rs/ahash/0.8.3/ahash/random_state/struct.RandomState.html#method.with_seeds)
which is the proper way to get a fixed hasher (see [this
table](https://docs.rs/ahash/0.8.3/ahash/random_state/struct.RandomState.html)).
This means that hashes won't be the same across versions

---

## Migration Guide

- If you were using hashes to an asset or using one of the fixed hasher
exposed by Bevy with a previous version, you will have to update the
hashes
2023-05-23 02:17:07 +00:00
JMS55
17f045e2a0
Delay asset hot reloading (#8503)
# Objective

- Fix #5631 

## Solution

- Wait 50ms (configurable) after the last modification event before
reloading an asset.

---

## Changelog

- `AssetPlugin::watch_for_changes` is now a `ChangeWatcher` instead of a
`bool`
- Fixed https://github.com/bevyengine/bevy/issues/5631

## Migration Guide
- Replace `AssetPlugin::watch_for_changes: true` with e.g.
`ChangeWatcher::with_delay(Duration::from_millis(200))`

---------

Co-authored-by: François <mockersf@gmail.com>
2023-05-16 01:26:11 +00:00
Mincho Paskalev
fe57b9f744
Add Reflect and FromReflect for AssetPath (#8531)
# Objective

- Add Reflect and FromReflect for AssetPath
- Fixes #8458

## Solution

- Straightforward derive of `Reflect` and `FromReflect` for `AssetPath`
- Implement `Reflect` and `FromReflect` for `Cow<'static, Path>` as to
satisfy the 'static lifetime requierments of bevy_reflect.
Implementation is a direct copy of that for `Cow<'static, str>` so maybe
it begs the question that was already asked in #7429 - maybe it would be
benefitial to write a general implementation for `Reflect` for
`Cow<'static, T>`.
2023-05-08 19:19:19 +00:00
konsti219
1530f63756
Use cmp of Self in implementaions of partial_cmp (#8559)
# Objective

Ensure future consistency between the two compare functions for all
types with manual `Ord` and `PartialOrd` implementations.

## Solution

Use `Self::cpm` in the implementation of `partial_cpm` for types
`Handle` and `Name`.
2023-05-06 22:31:25 +00:00
Gino Valente
6df65a2aa8
bevy_asset: Add LoadContext::get_handle_untyped (#8470)
# Objective

Currently, there isn't a clean way of getting an untyped handle to an
asset during asset loading. This is useful for when an asset needs to
reference other assets, but may not know the concrete type of each
asset.

We could "hack" this together by just using some random asset:

```rust
// We don't care what `bar.baz` is, so we "pretend" it's an `Image`
let handle: Handle<Image> = load_context.get_handle("foo/bar.baz");
```

This should work since we don't actually care about the underlying type
in this case. However, we can do better.

## Solution

Add the `LoadContext::get_handle_untyped` method to get untyped handles
to assets.
2023-04-25 19:32:34 +00:00
Wybe Westra
abf12f3b3b
Fixed several missing links in docs. (#8117)
Links in the api docs are nice. I noticed that there were several places
where structs / functions and other things were referenced in the docs,
but weren't linked. I added the links where possible / logical.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François <mockersf@gmail.com>
2023-04-23 17:28:36 +00:00
JoJoJet
3ead10a3e0
Suppress the clippy::type_complexity lint (#8313)
# Objective

The clippy lint `type_complexity` is known not to play well with bevy.
It frequently triggers when writing complex queries, and taking the
lint's advice of using a type alias almost always just obfuscates the
code with no benefit. Because of this, this lint is currently ignored in
CI, but unfortunately it still shows up when viewing bevy code in an
IDE.

As someone who's made a fair amount of pull requests to this repo, I
will say that this issue has been a consistent thorn in my side. Since
bevy code is filled with spurious, ignorable warnings, it can be very
difficult to spot the *real* warnings that must be fixed -- most of the
time I just ignore all warnings, only to later find out that one of them
was real after I'm done when CI runs.

## Solution

Suppress this lint in all bevy crates. This was previously attempted in
#7050, but the review process ended up making it more complicated than
it needs to be and landed on a subpar solution.

The discussion in https://github.com/rust-lang/rust-clippy/pull/10571
explores some better long-term solutions to this problem. Since there is
no timeline on when these solutions may land, we should resolve this
issue in the meantime by locally suppressing these lints.

### Unresolved issues

Currently, these lints are not suppressed in our examples, since that
would require suppressing the lint in every single source file. They are
still ignored in CI.
2023-04-06 21:27:36 +00:00
Carter Anderson
aefe1f0739
Schedule-First: the new and improved add_systems (#8079)
Co-authored-by: Mike <mike.hsu@gmail.com>
2023-03-18 01:45:34 +00:00
sark
520e413c21
unused_variables warning when building with filesystem_watcher feature disabled (#7938) 2023-03-14 08:58:55 +00:00
JoJoJet
fd1af7c8b8
Replace multiple calls to add_system with add_systems (#8001) 2023-03-10 18:15:22 +00:00
SpecificProtagonist
91ff782439 Fix hot reloading for read_asset_bytes (#6797)
# Objective

Fixes #6780

## Solution

- record the asset path of each watched file
- call `AssetIo::watch_for_changes` in `LoadContext::read_asset_bytes`

---

## Changelog

### Fixed
- fixed hot reloading for `LoadContext::read_asset_bytes`

### Changed
- `AssetIo::watch_path_for_changes` allows watched path and path to reload to differ

## Migration Guide
- for custom `AssetIo`s, differentiate paths to watch and asset paths to reload as a consequence

Co-authored-by: Vincent Junge <specificprotagonist@posteo.org>
2023-03-02 02:51:06 +00:00
shuo
002c9d8b7f fix whitespaces in comment (#7853)
fix double whitespaces in comments. (I know it's dumb commit, while reading code, double spaces hurts a little... :P)
2023-03-01 10:20:56 +00:00
Rob Parrett
b39f83640f Fix some typos (#7763)
# Objective

Stumbled on a typo and went on a typo hunt.

## Solution

Fix em
2023-02-20 22:56:57 +00:00
TimJentzsch
9b7060c4d2 Make StartupSet a base set (#7574)
# Objective

Closes #7573

- Make `StartupSet` a base set

## Solution

- Add `#[system_set(base)]` to the enum declaration
- Replace `.in_set(StartupSet::...)` with `.in_base_set(StartupSet::...)`

**Note**: I don't really know what I'm doing and what exactly the difference between base and non-base sets are. I mostly opened this PR based on discussion in Discord. I also don't really know how to test that I didn't break everything. Your reviews are appreciated!

---

## Changelog

- `StartupSet` is now a base set

## Migration Guide

`StartupSet` is now a base set. This means that you have to use `.in_base_set` instead of `.in_set`:

### Before

```rs
app.add_system(foo.in_set(StartupSet::PreStartup))
```

### After

```rs
app.add_system(foo.in_base_set(StartupSet::PreStartup))
```
2023-02-19 03:10:06 +00:00
Niklas Eicker
0bce78439b Cleanup system sets called labels (#7678)
# Objective

We have a few old system labels that are now system sets but are still named or documented as labels. Documentation also generally mentioned system labels in some places.


## Solution

- Clean up naming and documentation regarding system sets

## Migration Guide

`PrepareAssetLabel` is now called `PrepareAssetSet`
2023-02-14 21:46:07 +00:00
JMS55
5a152d7d75 Fix crash with debug_asset_server due to base set changes (#7538) 2023-02-07 14:18:15 +00:00
Carter Anderson
dcc03724a5 Base Sets (#7466)
# Objective

NOTE: This depends on #7267 and should not be merged until #7267 is merged. If you are reviewing this before that is merged, I highly recommend viewing the Base Sets commit instead of trying to find my changes amongst those from #7267.

"Default sets" as described by the [Stageless RFC](https://github.com/bevyengine/rfcs/pull/45) have some [unfortunate consequences](https://github.com/bevyengine/bevy/discussions/7365).

## Solution

This adds "base sets" as a variant of `SystemSet`:

A set is a "base set" if `SystemSet::is_base` returns `true`. Typically this will be opted-in to using the `SystemSet` derive:

```rust
#[derive(SystemSet, Clone, Hash, Debug, PartialEq, Eq)]
#[system_set(base)]
enum MyBaseSet {
  A,
  B,
}
``` 

**Base sets are exclusive**: a system can belong to at most one "base set". Adding a system to more than one will result in an error. When possible we fail immediately during system-config-time with a nice file + line number. For the more nested graph-ey cases, this will fail at the final schedule build. 

**Base sets cannot belong to other sets**: this is where the word "base" comes from

Systems and Sets can only be added to base sets using `in_base_set`. Calling `in_set` with a base set will fail. As will calling `in_base_set` with a normal set.

```rust
app.add_system(foo.in_base_set(MyBaseSet::A))
       // X must be a normal set ... base sets cannot be added to base sets
       .configure_set(X.in_base_set(MyBaseSet::A))
```

Base sets can still be configured like normal sets:

```rust
app.add_system(MyBaseSet::B.after(MyBaseSet::Ap))
``` 

The primary use case for base sets is enabling a "default base set":

```rust
schedule.set_default_base_set(CoreSet::Update)
  // this will belong to CoreSet::Update by default
  .add_system(foo)
  // this will override the default base set with PostUpdate
  .add_system(bar.in_base_set(CoreSet::PostUpdate))
```

This allows us to build apis that work by default in the standard Bevy style. This is a rough analog to the "default stage" model, but it use the new "stageless sets" model instead, with all of the ordering flexibility (including exclusive systems) that it provides.

---

## Changelog

- Added "base sets" and ported CoreSet to use them.

## Migration Guide

TODO
2023-02-06 03:10:08 +00:00
Alice Cecile
206c7ce219 Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.

# Objective

- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45

## Solution

- [x]  Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests

## Changelog

### Added

- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`

### Removed

- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.

### Changed

- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
-  `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. 
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.

## Migration Guide

- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage`  enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
  - Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
  - Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
  - For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with 
  - `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`

## TODO

- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
  - [x] unbreak directional lights
  - [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
  - [x] game menu example shows loading screen and menu simultaneously
  - [x] display settings menu is a blank screen
  - [x] `without_winit` example panics
- [x] ensure all tests pass
  - [x] SubApp doc test fails
  - [x] runs_spawn_local tasks fails
  - [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)

## Points of Difficulty and Controversy

**Reviewers, please give feedback on these and look closely**

1.  Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.

## Future Work (ideally before 0.10)

- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
François
3900b48c88 update winit to 0.28 (#7480)
# Objective

- Update winit to 0.28

## Solution

- Small API change 
- A security advisory has been added for a unmaintained crate used by a dependency of winit build script for wayland

I didn't do anything for Android support in this PR though it should be fixable, it should be done in a separate one, maybe https://github.com/bevyengine/bevy/pull/6830 

---

## Changelog

- `window.always_on_top` has been removed, you can now use `window.window_level`

## Migration Guide

before:
```rust
    app.new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                always_on_top: true,
                ..default()
            }),
            ..default()
        }));
```

after:
```rust
    app.new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                window_level: bevy:🪟:WindowLevel::AlwaysOnTop,
                ..default()
            }),
            ..default()
        }));
```
2023-02-03 16:41:39 +00:00
MinerSebas
1a18ab34c4 Remove unnecessary Default impl of HandleType (#7472)
# Objective

- Resolve a Fixme to remove the `Default` impl for `HandleType`, once Reflection no longer requires it.
- Presumebly this Comment was made before the `FromReflect` Derive used the `#[reflect(Default)]`, to substitute for the requirment that a ignored field has a `Default`.

## Solution

- Just remove the `Default` derive and comment.
2023-02-02 15:09:06 +00:00
Jakob Hellermann
0cb0d8b55d add UnsafeWorldCell abstraction (#6404)
alternative to #5922, implements #5956 
builds on top of https://github.com/bevyengine/bevy/pull/6402

# Objective

https://github.com/bevyengine/bevy/issues/5956 goes into more detail, but the TLDR is:
- bevy systems ensure disjoint accesses to resources and components, and for that to work there are methods `World::get_resource_unchecked_mut(&self)`, ..., `EntityRef::get_mut_unchecked(&self)` etc.
- we don't have these unchecked methods for `by_id` variants, so third-party crate authors cannot build their own safe disjoint-access abstractions with these
- having `_unchecked_mut` methods is not great, because in their presence safe code can accidentally violate subtle invariants. Having to go through `world.as_unsafe_world_cell().unsafe_method()` forces you to stop and think about what you want to write in your `// SAFETY` comment.

The alternative is to keep exposing `_unchecked_mut` variants for every operation that we want third-party crates to build upon, but we'd prefer to avoid using these methods alltogether: https://github.com/bevyengine/bevy/pull/5922#issuecomment-1241954543

Also, this is something that **cannot be implemented outside of bevy**, so having either this PR or #5922 as an escape hatch with lots of discouraging comments would be great.

## Solution

- add `UnsafeWorldCell` with `unsafe fn get_resource(&self)`, `unsafe fn get_resource_mut(&self)`
- add `fn World::as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_>` (and `as_unsafe_world_cell_readonly(&self)`)
- add `UnsafeWorldCellEntityRef` with `unsafe fn get`, `unsafe fn get_mut` and the other utilities on `EntityRef` (no methods for spawning, despawning, insertion)
- use the `UnsafeWorldCell` abstraction in `ReflectComponent`, `ReflectResource` and `ReflectAsset`, so these APIs are easier to reason about
- remove `World::get_resource_mut_unchecked`, `EntityRef::get_mut_unchecked` and use `unsafe { world.as_unsafe_world_cell().get_mut() }` and `unsafe { world.as_unsafe_world_cell().get_entity(entity)?.get_mut() }` instead

This PR does **not** make use of `UnsafeWorldCell` for anywhere else in `bevy_ecs` such as `SystemParam` or `Query`. That is a much larger change, and I am convinced that having `UnsafeWorldCell` is already useful for third-party crates.

Implemented API:

```rust
struct World { .. }
impl World {
  fn as_unsafe_world_cell(&self) -> UnsafeWorldCell<'_>;
}

struct UnsafeWorldCell<'w>(&'w World);
impl<'w> UnsafeWorldCell {
  unsafe fn world(&self) -> &World;

  fn get_entity(&self) -> UnsafeWorldCellEntityRef<'w>; // returns 'w which is `'self` of the `World::as_unsafe_world_cell(&'w self)`

  unsafe fn get_resource<T>(&self) -> Option<&'w T>;
  unsafe fn get_resource_by_id(&self, ComponentId) -> Option<&'w T>;
  unsafe fn get_resource_mut<T>(&self) -> Option<Mut<'w, T>>;
  unsafe fn get_resource_mut_by_id(&self) -> Option<MutUntyped<'w>>;
  unsafe fn get_non_send_resource<T>(&self) -> Option<&'w T>;
  unsafe fn get_non_send_resource_mut<T>(&self) -> Option<Mut<'w, T>>>;

  // not included: remove, remove_resource, despawn, anything that might change archetypes
}

struct UnsafeWorldCellEntityRef<'w> { .. }
impl UnsafeWorldCellEntityRef<'w> {
  unsafe fn get<T>(&self, Entity) -> Option<&'w T>;
  unsafe fn get_by_id(&self, Entity, ComponentId) -> Option<Ptr<'w>>;
  unsafe fn get_mut<T>(&self, Entity) -> Option<Mut<'w, T>>;
  unsafe fn get_mut_by_id(&self, Entity, ComponentId) -> Option<MutUntyped<'w>>;
  unsafe fn get_change_ticks<T>(&self, Entity) -> Option<Mut<'w, T>>;
  // fn id, archetype, contains, contains_id, containts_type_id
}
```

<details>
<summary>UnsafeWorldCell docs</summary>

Variant of the [`World`] where resource and component accesses takes a `&World`, and the responsibility to avoid
aliasing violations are given to the caller instead of being checked at compile-time by rust's unique XOR shared rule.

### Rationale
In rust, having a `&mut World` means that there are absolutely no other references to the safe world alive at the same time,
without exceptions. Not even unsafe code can change this.

But there are situations where careful shared mutable access through a type is possible and safe. For this, rust provides the [`UnsafeCell`](std::cell::UnsafeCell)
escape hatch, which allows you to get a `*mut T` from a `&UnsafeCell<T>` and around which safe abstractions can be built.

Access to resources and components can be done uniquely using [`World::resource_mut`] and [`World::entity_mut`], and shared using [`World::resource`] and [`World::entity`].
These methods use lifetimes to check at compile time that no aliasing rules are being broken.

This alone is not enough to implement bevy systems where multiple systems can access *disjoint* parts of the world concurrently. For this, bevy stores all values of
resources and components (and [`ComponentTicks`](crate::component::ComponentTicks)) in [`UnsafeCell`](std::cell::UnsafeCell)s, and carefully validates disjoint access patterns using
APIs like [`System::component_access`](crate::system::System::component_access).

A system then can be executed using [`System::run_unsafe`](crate::system::System::run_unsafe) with a `&World` and use methods with interior mutability to access resource values.
access resource values.

### Example Usage

[`UnsafeWorldCell`] can be used as a building block for writing APIs that safely allow disjoint access into the world.
In the following example, the world is split into a resource access half and a component access half, where each one can
safely hand out mutable references.

```rust
use bevy_ecs::world::World;
use bevy_ecs::change_detection::Mut;
use bevy_ecs::system::Resource;
use bevy_ecs::world::unsafe_world_cell_world::UnsafeWorldCell;

// INVARIANT: existance of this struct means that users of it are the only ones being able to access resources in the world
struct OnlyResourceAccessWorld<'w>(UnsafeWorldCell<'w>);
// INVARIANT: existance of this struct means that users of it are the only ones being able to access components in the world
struct OnlyComponentAccessWorld<'w>(UnsafeWorldCell<'w>);

impl<'w> OnlyResourceAccessWorld<'w> {
    fn get_resource_mut<T: Resource>(&mut self) -> Option<Mut<'w, T>> {
        // SAFETY: resource access is allowed through this UnsafeWorldCell
        unsafe { self.0.get_resource_mut::<T>() }
    }
}
// impl<'w> OnlyComponentAccessWorld<'w> {
//     ...
// }

// the two interior mutable worlds borrow from the `&mut World`, so it cannot be accessed while they are live
fn split_world_access(world: &mut World) -> (OnlyResourceAccessWorld<'_>, OnlyComponentAccessWorld<'_>) {
    let resource_access = OnlyResourceAccessWorld(unsafe { world.as_unsafe_world_cell() });
    let component_access = OnlyComponentAccessWorld(unsafe { world.as_unsafe_world_cell() });
    (resource_access, component_access)
}
```


</details>
2023-01-27 00:12:13 +00:00
IceSentry
4ff50f6b50 fix load_internal_binary_asset with debug_asset_server (#7246)
# Objective

- Enabling the `debug_asset_server` feature doesn't compile when using it with `load_internal_binary_asset!()`. The issue is because it assumes the loader takes an `&'static str` as a parameter, but binary assets loader expect `&'static [u8]`.

## Solution

- Add a generic type for the loader and use a different type in `load_internal_asset` and `load_internal_binary_asset`
2023-01-18 02:07:26 +00:00
Thierry Berger
83028994d1 Optional BEVY_ASSET_ROOT to find assets directory (#5346)
# Objective

Fixes #5345

## Changelog

- Support optional env variable `BEVY_ASSET_ROOT` to explicitly specify root assets directory.
2023-01-16 17:36:09 +00:00
张林伟
0d2cdb450d Fix beta clippy lints (#7154)
# Objective

- When I run `cargo run -p ci` for my pr locally using latest beta toolchain, the ci failed due to [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) and [needless_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes) lints

## Solution

- Fix lints according to clippy suggestions.
2023-01-11 09:51:22 +00:00
Rob Parrett
3dd8b42f72 Fix various typos (#7096)
I stumbled across a typo in some docs. Fixed some more while I was in there.
2023-01-06 00:43:30 +00:00
targrub
329b71fa62 Break CorePlugin into TaskPoolPlugin, TypeRegistrationPlugin, FrameCountPlugin. (#7083)
# Objective

- Fixes #7081.

## Solution

- Moved functionality from kitchen sink plugin `CorePlugin` to separate plugins, `TaskPoolPlugin`, `TypeRegistrationPlugin`, `FrameCountPlugin`.  `TaskPoolOptions` resource should now be used with `TaskPoolPlugin`.

## Changelog

Minimal changes made (code kept in `bevy_core/lib.rs`).

## Migration Guide

- `CorePlugin` broken into separate plugins.  If not using `DefaultPlugins` or `MinimalPlugins` `PluginGroup`s, the replacement for `CorePlugin` is now to add `TaskPoolPlugin`, `TypeRegistrationPlugin`, and `FrameCountPlugin` to the app.

## Notes

- Consistent with Bevy goal "modularity over deep integration" but the functionality of `TypeRegistrationPlugin` and `FrameCountPlugin` is weak (the code has to go somewhere, though!).
- No additional tests written.
2023-01-05 11:42:35 +00:00
Matthias Schiffer
85743ce49e asset: make HandleUntyped::id private (#7076)
# Objective

It is currently possible to break reference counting for assets by creating a strong `HandleUntyped` and then modifying the `id` field before dropping the handle. This should not be allowed.

## Solution

Change the `id` field visibility to private and add a getter instead. The same change was previously done for `Handle<T>` in #6176, but `HandleUntyped` was forgotten.

---

## Migration Guide

- Instead of directly accessing the ID of a `HandleUntyped` as `handle.id`, use the new getter `handle.id()`.
2023-01-04 23:40:43 +00:00
Johan Klokkhammer Helsing
69011b7e26 Derive clone and debug for AssetPlugin (#6583)
# Objective

- Derive Clone and Debug for `AssetPlugin`
- Make it possible to log asset server settings
- And get an owned instance if wrapping `AssetPlugin` in another plugin. See: 129224ef72/src/web_asset_plugin.rs (L45)
2022-11-14 23:08:26 +00:00
研究社交
0aa17d0aca Macro for Loading Internal Binary Assets (#6478)
# Objective

The `load_internal_asset` macro is helpful when creating rendering plugins, but it doesn't support load binary assets (like those compiled as spir-v).

## Solution

Add a `load_internal_binary_asset` macro that use `include_bytes!`.
2022-11-07 19:44:15 +00:00
TimJentzsch
694c980c82 Fix clippy::iter_with_drain (#6485)
# Objective

Fixes #6483.

- Fix the [`clippy::iter_with_drain`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain) warnings
- From the docs: "`.into_iter()` is simpler with better performance"

## Solution

- Replace `.drain(..)` for `Vec` with `.into_iter()`
2022-11-06 01:42:15 +00:00
Alice Cecile
334e09892b Revert "Show prelude re-exports in docs (#6448)" (#6449)
This reverts commit 53d387f340.

# Objective

Reverts #6448. This didn't have the intended effect: we're now getting bevy::prelude shown in the docs again.

Co-authored-by: Alejandro Pascual <alejandro.pascual.pozo@gmail.com>
2022-11-02 20:40:45 +00:00
Alejandro Pascual
53d387f340 Show prelude re-exports in docs (#6448)
# Objective

- Right now re-exports are completely hidden in prelude docs.
- Fixes #6433

## Solution

- We could show the re-exports without inlining their documentation.
2022-11-02 19:35:06 +00:00