From 46762ef0d3764860ffb98a97c1c39c3f2705a3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Tue, 23 Jan 2024 15:40:05 +0100 Subject: [PATCH 1/8] Add directory related functions to `AndroidAssetReader` This fixes #9968 --- crates/bevy_asset/src/io/android.rs | 49 +++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index f792a72b00383..deb33e9943358 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -3,14 +3,16 @@ use crate::io::{ }; use bevy_log::error; use bevy_utils::BoxedFuture; +use futures_lite::stream; use std::{ffi::CString, path::Path}; /// [`AssetReader`] implementation for Android devices, built on top of Android's [`AssetManager`]. /// /// Implementation details: /// -/// - [`load_path`](AssetIo::load_path) uses the [`AssetManager`] to load files. -/// - [`read_directory`](AssetIo::read_directory) always returns an empty iterator. +/// - All functions use the [`AssetManager`] to load files. +/// - [`is_directory`](AssetReader::is_directory) tris to open the path +/// as a normal file and treats error as if the path is directory. /// - Watching for changes is not supported. The watcher method will do nothing. /// /// [AssetManager]: https://developer.android.com/reference/android/content/res/AssetManager @@ -56,18 +58,47 @@ impl AssetReader for AndroidAssetReader { fn read_directory<'a>( &'a self, - _path: &'a Path, + path: &'a Path, ) -> BoxedFuture<'a, Result, AssetReaderError>> { - let stream: Box = Box::new(EmptyPathStream); - error!("Reading directories is not supported with the AndroidAssetReader"); - Box::pin(async move { Ok(stream) }) + Box::pin(async move { + let asset_manager = bevy_winit::ANDROID_APP + .get() + .expect("Bevy must be setup with the #[bevy_main] macro on Android") + .asset_manager(); + let mut opened_assets_dir = asset_manager + .open_dir(&CString::new(path.to_str().unwrap()).unwrap()) + .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; + + let mapped_stream = opened_assets_dir + .filter_map(move |f| { + let file_path = path.join(Path::new(f.to_str().unwrap())); + // filter out meta files as they are not considered assets + if let Some(ext) = file_path.extension().and_then(|e| e.to_str()) { + if ext.eq_ignore_ascii_case("meta") { + return None; + } + } + Some(file_path.to_owned()) + }) + .collect::>(); + + let read_dir: Box = Box::new(stream::iter(mapped_stream)); + Ok(read_dir) + }) } fn is_directory<'a>( &'a self, - _path: &'a Path, + path: &'a Path, ) -> BoxedFuture<'a, std::result::Result> { - error!("Reading directories is not supported with the AndroidAssetReader"); - Box::pin(async move { Ok(false) }) + Box::pin(async move { + let asset_manager = bevy_winit::ANDROID_APP + .get() + .expect("Bevy must be setup with the #[bevy_main] macro on Android") + .asset_manager(); + Ok(asset_manager + .open(&CString::new(path.to_str().unwrap()).unwrap()) + .map_or(true, |_| false)) + }) } } From 95d8f08f5f7275abe7bd0a193d2d1de745d24fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Wed, 24 Jan 2024 12:31:08 +0100 Subject: [PATCH 2/8] Fix warnings in AndroidAssetReader --- crates/bevy_asset/src/io/android.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index deb33e9943358..81d69b557f0d4 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -1,7 +1,4 @@ -use crate::io::{ - get_meta_path, AssetReader, AssetReaderError, EmptyPathStream, PathStream, Reader, VecReader, -}; -use bevy_log::error; +use crate::io::{get_meta_path, AssetReader, AssetReaderError, PathStream, Reader, VecReader}; use bevy_utils::BoxedFuture; use futures_lite::stream; use std::{ffi::CString, path::Path}; @@ -65,7 +62,7 @@ impl AssetReader for AndroidAssetReader { .get() .expect("Bevy must be setup with the #[bevy_main] macro on Android") .asset_manager(); - let mut opened_assets_dir = asset_manager + let opened_assets_dir = asset_manager .open_dir(&CString::new(path.to_str().unwrap()).unwrap()) .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; From dc8db07bf6f4002911f38bd8f3e4ca8a102dff66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Thu, 25 Jan 2024 15:15:55 +0100 Subject: [PATCH 3/8] Fix typos in `AndroidAssetReader` docs --- crates/bevy_asset/src/io/android.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index 81d69b557f0d4..276e8c3cfa898 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -8,8 +8,8 @@ use std::{ffi::CString, path::Path}; /// Implementation details: /// /// - All functions use the [`AssetManager`] to load files. -/// - [`is_directory`](AssetReader::is_directory) tris to open the path -/// as a normal file and treats error as if the path is directory. +/// - [`is_directory`](AssetReader::is_directory) tries to open the path +/// as a normal file and treats an error as if the path is a directory. /// - Watching for changes is not supported. The watcher method will do nothing. /// /// [AssetManager]: https://developer.android.com/reference/android/content/res/AssetManager From 2e0ba1d2fd65469bc5c6372016f4b3621da4c33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Fri, 26 Jan 2024 09:14:41 +0100 Subject: [PATCH 4/8] Add `open_dir` to `is_directory` to propagate file not found errors too --- crates/bevy_asset/src/io/android.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index 276e8c3cfa898..f5215577562c1 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -93,6 +93,17 @@ impl AssetReader for AndroidAssetReader { .get() .expect("Bevy must be setup with the #[bevy_main] macro on Android") .asset_manager(); + // HACK: `AssetManager` does not provide a way to check if path + // points to a directory or a file + // `open_dir` succeeds for both files and directories and will only + // fail if the path does not exist at all + // `open` will fail for directories, but it will work for files + // The solution here was to first use `open_dir` to eliminate the case + // when the path does not exist at all, and then to use `open` to + // see if that path is a file or a directory + let _ = asset_manager + .open_dir(&CString::new(path.to_str().unwrap()).unwrap()) + .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; Ok(asset_manager .open(&CString::new(path.to_str().unwrap()).unwrap()) .map_or(true, |_| false)) From 58d120d65ee1a108ef4ebb630686f670a1eed256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Fri, 26 Jan 2024 10:40:02 +0100 Subject: [PATCH 5/8] Use `is_none` instead of `map_or` Co-authored-by: Kanabenki --- crates/bevy_asset/src/io/android.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index f5215577562c1..5d190439ee778 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -106,7 +106,7 @@ impl AssetReader for AndroidAssetReader { .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; Ok(asset_manager .open(&CString::new(path.to_str().unwrap()).unwrap()) - .map_or(true, |_| false)) + .is_none() }) } } From 3704a72d846f5da15fa1331cc8b1f98322141179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Fri, 26 Jan 2024 10:55:57 +0100 Subject: [PATCH 6/8] Add missing closing delimiter for `Ok` in `is_directory` --- crates/bevy_asset/src/io/android.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index 5d190439ee778..a487db07a1dab 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -106,7 +106,7 @@ impl AssetReader for AndroidAssetReader { .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; Ok(asset_manager .open(&CString::new(path.to_str().unwrap()).unwrap()) - .is_none() + .is_none()) }) } } From 0d13ee135e7ee732856c76e8a1f692515e73663d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Wed, 13 Mar 2024 09:30:51 +0100 Subject: [PATCH 7/8] Remove duplicate path creation in `is_directory` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Mockers --- crates/bevy_asset/src/io/android.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index 69a7069ecc6bb..0d27e2596f1af 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -102,12 +102,11 @@ impl AssetReader for AndroidAssetReader { // The solution here was to first use `open_dir` to eliminate the case // when the path does not exist at all, and then to use `open` to // see if that path is a file or a directory + let path = CString::new(path.to_str().unwrap()).unwrap(); let _ = asset_manager - .open_dir(&CString::new(path.to_str().unwrap()).unwrap()) + .open_dir(&path) .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; - Ok(asset_manager - .open(&CString::new(path.to_str().unwrap()).unwrap()) - .is_none()) + Ok(asset_manager.open(&path).is_none()) }) } } From 573a6f1c6f4035f84f19ff746263aa7bcf5c75d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Wed, 25 Sep 2024 10:46:19 +0200 Subject: [PATCH 8/8] Fix shadowing `path` in android asset manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Mockers --- crates/bevy_asset/src/io/android.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_asset/src/io/android.rs b/crates/bevy_asset/src/io/android.rs index c9ace19bf9fbf..c1f3a9b1a28fb 100644 --- a/crates/bevy_asset/src/io/android.rs +++ b/crates/bevy_asset/src/io/android.rs @@ -88,10 +88,10 @@ impl AssetReader for AndroidAssetReader { // The solution here was to first use `open_dir` to eliminate the case // when the path does not exist at all, and then to use `open` to // see if that path is a file or a directory - let path = CString::new(path.to_str().unwrap()).unwrap(); + let cpath = CString::new(path.to_str().unwrap()).unwrap(); let _ = asset_manager - .open_dir(&path) + .open_dir(&cpath) .ok_or(AssetReaderError::NotFound(path.to_path_buf()))?; - Ok(asset_manager.open(&path).is_none()) + Ok(asset_manager.open(&cpath).is_none()) } }