Skip to content

Commit cbf989c

Browse files
atlv24mrchanteymockersfalice-i-cecilejf908
authored
WebAssets without filtering (#20628)
# Objective - adopt #17889 - Fixes #5061 --------- Co-authored-by: Peter Hayman <[email protected]> Co-authored-by: François Mockers <[email protected]> Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: jf908 <[email protected]> Co-authored-by: François Mockers <[email protected]> Co-authored-by: jf908 <[email protected]>
1 parent 8d33e75 commit cbf989c

File tree

13 files changed

+439
-6
lines changed

13 files changed

+439
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Cargo.lock
2222
assets/**/*.meta
2323
crates/bevy_asset/imported_assets
2424
imported_assets
25+
.web-asset-cache
2526

2627
# Bevy Examples
2728
example_showcase_config.ron

Cargo.toml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,15 @@ file_watcher = ["bevy_internal/file_watcher"]
515515
# Enables watching in memory asset providers for Bevy Asset hot-reloading
516516
embedded_watcher = ["bevy_internal/embedded_watcher"]
517517

518+
# Enables downloading assets from HTTP sources. Warning: there are security implications. Read the docs on WebAssetPlugin.
519+
http = ["bevy_internal/http"]
520+
521+
# Enables downloading assets from HTTPS sources. Warning: there are security implications. Read the docs on WebAssetPlugin.
522+
https = ["bevy_internal/https"]
523+
524+
# Enable caching downloaded assets on the filesystem. NOTE: this cache currently never invalidates entries!
525+
web_asset_cache = ["bevy_internal/web_asset_cache"]
526+
518527
# Enable stepping-based debugging of Bevy systems
519528
bevy_debug_stepping = [
520529
"bevy_internal/bevy_debug_stepping",
@@ -1911,12 +1920,24 @@ path = "examples/asset/extra_source.rs"
19111920
doc-scrape-examples = true
19121921

19131922
[package.metadata.example.extra_asset_source]
1914-
name = "Extra asset source"
1923+
name = "Extra Asset Source"
19151924
description = "Load an asset from a non-standard asset source"
19161925
category = "Assets"
19171926
# Uses non-standard asset path
19181927
wasm = false
19191928

1929+
[[example]]
1930+
name = "web_asset"
1931+
path = "examples/asset/web_asset.rs"
1932+
doc-scrape-examples = true
1933+
required-features = ["https"]
1934+
1935+
[package.metadata.example.web_asset]
1936+
name = "Web Asset"
1937+
description = "Load an asset from the web"
1938+
category = "Assets"
1939+
wasm = true
1940+
19201941
[[example]]
19211942
name = "hot_asset_reloading"
19221943
path = "examples/asset/hot_asset_reloading.rs"

crates/bevy_asset/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ keywords = ["bevy"]
1414
file_watcher = ["notify-debouncer-full", "watch", "multi_threaded"]
1515
embedded_watcher = ["file_watcher"]
1616
multi_threaded = ["bevy_tasks/multi_threaded"]
17+
http = ["blocking", "ureq"]
18+
https = ["blocking", "ureq", "ureq/rustls"]
19+
web_asset_cache = []
1720
asset_processor = []
1821
watch = []
1922
trace = []
@@ -87,6 +90,9 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-featu
8790

8891
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
8992
notify-debouncer-full = { version = "0.5.0", default-features = false, optional = true }
93+
# updating ureq: while ureq is semver stable, it depends on rustls which is not, meaning unlikely but possible breaking changes on minor releases. https://github.com/bevyengine/bevy/pull/16366#issuecomment-2572890794
94+
ureq = { version = "3", optional = true, default-features = false }
95+
blocking = { version = "1.6", optional = true }
9096

9197
[dev-dependencies]
9298
async-channel = "2"

crates/bevy_asset/src/io/mod.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub mod memory;
1414
pub mod processor_gated;
1515
#[cfg(target_arch = "wasm32")]
1616
pub mod wasm;
17+
#[cfg(any(feature = "http", feature = "https"))]
18+
pub mod web;
1719

1820
#[cfg(test)]
1921
pub mod gated;
@@ -48,7 +50,8 @@ pub enum AssetReaderError {
4850
Io(Arc<std::io::Error>),
4951

5052
/// The HTTP request completed but returned an unhandled [HTTP response status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
51-
/// If the request fails before getting a status code (e.g. request timeout, interrupted connection, etc), expect [`AssetReaderError::Io`].
53+
/// - If the request returns a 404 error, expect [`AssetReaderError::NotFound`].
54+
/// - If the request fails before getting a status code (e.g. request timeout, interrupted connection, etc), expect [`AssetReaderError::Io`].
5255
#[error("Encountered HTTP status {0:?} when loading asset")]
5356
HttpError(u16),
5457
}
@@ -764,11 +767,16 @@ impl Reader for SliceReader<'_> {
764767
}
765768
}
766769

767-
/// Appends `.meta` to the given path.
770+
/// Appends `.meta` to the given path:
771+
/// - `foo` becomes `foo.meta`
772+
/// - `foo.bar` becomes `foo.bar.meta`
768773
pub(crate) fn get_meta_path(path: &Path) -> PathBuf {
769774
let mut meta_path = path.to_path_buf();
770775
let mut extension = path.extension().unwrap_or_default().to_os_string();
771-
extension.push(".meta");
776+
if !extension.is_empty() {
777+
extension.push(".");
778+
}
779+
extension.push("meta");
772780
meta_path.set_extension(extension);
773781
meta_path
774782
}
@@ -785,3 +793,24 @@ impl Stream for EmptyPathStream {
785793
Poll::Ready(None)
786794
}
787795
}
796+
797+
#[cfg(test)]
798+
mod tests {
799+
use super::*;
800+
801+
#[test]
802+
fn get_meta_path_no_extension() {
803+
assert_eq!(
804+
get_meta_path(Path::new("foo")).to_str().unwrap(),
805+
"foo.meta"
806+
);
807+
}
808+
809+
#[test]
810+
fn get_meta_path_with_extension() {
811+
assert_eq!(
812+
get_meta_path(Path::new("foo.bar")).to_str().unwrap(),
813+
"foo.bar.meta"
814+
);
815+
}
816+
}

crates/bevy_asset/src/io/wasm.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ fn js_value_to_err(context: &str) -> impl FnOnce(JsValue) -> std::io::Error + '_
5252
}
5353

5454
impl HttpWasmAssetReader {
55-
async fn fetch_bytes(&self, path: PathBuf) -> Result<impl Reader, AssetReaderError> {
55+
// Also used by [`WebAssetReader`](crate::web::WebAssetReader)
56+
pub(crate) async fn fetch_bytes(&self, path: PathBuf) -> Result<impl Reader, AssetReaderError> {
5657
// The JS global scope includes a self-reference via a specializing name, which can be used to determine the type of global context available.
5758
let global: Global = js_sys::global().unchecked_into();
5859
let promise = if !global.window().is_undefined() {

0 commit comments

Comments
 (0)