Commit graph

321 commits

Author SHA1 Message Date
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
github-actions[bot]
bf30a25efc
Release 0.12 (#10362)
Preparing next release
This PR has been auto-generated

---------

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François <mockersf@gmail.com>
2023-11-04 17:24:23 +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
Thierry Berger
442a316a1d
few fmt tweaks (#10264)
few format tweaks, initially spotted working on
https://github.com/bevyengine/bevy/pull/8745
2023-10-25 19:20:17 +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
dependabot[bot]
4eb9b9f7d7
Update notify-debouncer-full requirement from 0.2.0 to 0.3.1 (#9757)
Updates the requirements on
[notify-debouncer-full](https://github.com/notify-rs/notify) to permit
the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/notify-rs/notify/blob/main/CHANGELOG.md">notify-debouncer-full's
changelog</a>.</em></p>
<blockquote>
<h2>debouncer-full 0.3.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>debouncer-mini 0.4.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>notify 6.1.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>file-id 0.2.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/530">notify-rs/notify#530</a></p>
<h2>debouncer-full 0.3.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to dual-license of MIT OR Apache-2.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: upgrade to file-id 0.2.0 for high resolution file IDs <a
href="https://redirect.github.com/notify-rs/notify/issues/494">#494</a></li>
<li>FEATURE: derive debug for the debouncer struct <a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a></li>
</ul>
<h2>debouncer-mini 0.4.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to dual-license of MIT OR Apache-2.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: replace active polling with passive loop, removing empty
ticks <a
href="https://redirect.github.com/notify-rs/notify/issues/467">#467</a></li>
<li>FEATURE: derive debug for the debouncer struct <a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/467">#467</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/467">notify-rs/notify#467</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/510">notify-rs/notify#510</a></p>
<h2>notify 6.1.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to only CC0-1.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: use logging <a
href="https://redirect.github.com/notify-rs/notify/issues/499">#499</a></li>
<li>CHANGE: upgrade windows-sys to 0.48 <a
href="https://redirect.github.com/notify-rs/notify/issues/479">#479</a></li>
<li>CHANGE: bump filetime to 0.2.22 <a
href="https://redirect.github.com/notify-rs/notify/issues/521">#521</a></li>
<li>FEATURE: support manual polling of PollWatcher and disabling
automatic polling <a
href="https://redirect.github.com/notify-rs/notify/issues/524">#524</a></li>
<li>FEATURE: support listening to the initial pollwatcher file scan <a
href="https://redirect.github.com/notify-rs/notify/issues/507">#507</a></li>
<li>FIX: fix moved folders not being watched on linux <a
href="https://redirect.github.com/notify-rs/notify/issues/498">#498</a></li>
<li>FIX: fixup potential future double free on windows <a
href="https://redirect.github.com/notify-rs/notify/issues/517">#517</a></li>
<li>FIX: require bitflags only on macos and upgrade the crate <a
href="https://redirect.github.com/notify-rs/notify/issues/505">#505</a></li>
<li>DOCS: add more known issues, typos and cleanup examples <a
href="https://redirect.github.com/notify-rs/notify/issues/523">#523</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/502">#502</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/522">#522</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/524">#524</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/524">notify-rs/notify#524</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4a001215b3"><code>4a00121</code></a>
remove serde restriction and publish new versions</li>
<li><a
href="03ac300d36"><code>03ac300</code></a>
Fix a filename of example</li>
<li><a
href="2e971e59db"><code>2e971e5</code></a>
cleanup removed used-by entries</li>
<li><a
href="1cdf75fdc9"><code>1cdf75f</code></a>
fixup changelog to correct serde version</li>
<li>See full diff in <a
href="https://github.com/notify-rs/notify/compare/file-id-0.2.0...debouncer-full-0.3.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 22:10:20 +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
Christian Hughes
7a72bac779
Fix unused variable warning for simple AssetV2 derives (#9961)
# Objective

Fix #9960 

## Solution

Make the `visit` parameter `_visit` if there are no dependencies.

New `cargo expand` output:
```rust
pub struct Rarity {
    pub name: SharedStr,
    pub color: Color,
}
impl bevy::asset::Asset for Rarity {}
impl bevy::asset::VisitAssetDependencies for Rarity {
    fn visit_dependencies(
        &self,
        _visit: &mut impl FnMut(bevy::asset::UntypedAssetId), // <-- fixed
    ) {}
}
impl bevy::reflect::TypePath for Rarity {
    fn type_path() -> &'static str {
        "myasset::item::Rarity"
    }
    fn short_type_path() -> &'static str {
        "Rarity"
    }
    fn type_ident() -> Option<&'static str> {
        ::core::option::Option::Some("Rarity")
    }
    fn crate_name() -> Option<&'static str> {
        ::core::option::Option::Some(
            "myasset::item".split(':').next().unwrap(),
        )
    }
    fn module_path() -> Option<&'static str> {
        ::core::option::Option::Some("myasset::item")
    }
}
```
2023-09-29 08:08:13 +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