From aca088388b13a772daa62462eb7b7894411ef5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Sun, 12 Dec 2021 20:01:52 +0100 Subject: [PATCH 1/3] Update `assets_manager` to 0.7 --- Cargo.lock | 8 +- common/Cargo.toml | 2 +- common/assets/Cargo.toml | 2 +- common/assets/src/fs.rs | 91 +++++++++++ common/assets/src/lib.rs | 152 +++++-------------- common/src/bin/csv_import/main.rs | 20 ++- common/src/comp/body/ship.rs | 4 +- common/src/comp/inventory/item/mod.rs | 6 +- common/src/comp/inventory/item/tool.rs | 4 +- common/src/comp/inventory/loadout_builder.rs | 2 +- common/src/comp/inventory/trade_pricing.rs | 4 +- common/src/generation.rs | 2 +- common/src/recipe.rs | 6 +- common/src/terrain/structure.rs | 12 +- voxygen/Cargo.toml | 1 + voxygen/i18n/src/lib.rs | 23 +-- voxygen/i18n/src/raw.rs | 27 +--- voxygen/src/audio/music.rs | 4 +- voxygen/src/hud/item_imgs.rs | 6 +- voxygen/src/render/renderer.rs | 11 +- voxygen/src/render/renderer/shaders.rs | 4 +- voxygen/src/scene/figure/cache.rs | 12 +- voxygen/src/scene/figure/load.rs | 10 +- voxygen/src/scene/figure/volume.rs | 4 +- voxygen/src/ui/ice/cache.rs | 22 +-- world/src/layer/wildlife.rs | 2 +- world/src/sim/mod.rs | 9 +- 27 files changed, 223 insertions(+), 227 deletions(-) create mode 100644 common/assets/src/fs.rs diff --git a/Cargo.lock b/Cargo.lock index fae7714832..4f093f60e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,10 +214,11 @@ dependencies = [ [[package]] name = "assets_manager" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c55040a3eee1353bfa4bee2c03a695395d64176e8063223aa62d11b4ef669c" +checksum = "912acc83cc5bf31b0d9685e8d11a9d7c36b949e850ca2db1a3203b3b656a5e4a" dependencies = [ + "ab_glyph", "ahash 0.7.6", "bincode", "crossbeam-channel", @@ -6081,7 +6082,7 @@ dependencies = [ "petgraph 0.5.1", "rand 0.8.4", "rayon", - "ron 0.6.6", + "ron 0.7.0", "roots", "serde", "serde_repr", @@ -6358,6 +6359,7 @@ dependencies = [ name = "veloren-voxygen" version = "0.11.0" dependencies = [ + "assets_manager", "backtrace", "bincode", "bytemuck", diff --git a/common/Cargo.toml b/common/Cargo.toml index 8d45fb835d..911ab271f1 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -58,7 +58,7 @@ dot_vox = "4.0" serde_repr = "0.1.6" # csv import -ron = { version = "0.6", default-features = false, optional = true } +ron = { version = "0.7", default-features = false, optional = true } # csv export csv = { version = "1.1.3", optional = true } structopt = { version = "0.3.13", optional = true } diff --git a/common/assets/Cargo.toml b/common/assets/Cargo.toml index 52dc078b5e..92491bca90 100644 --- a/common/assets/Cargo.toml +++ b/common/assets/Cargo.toml @@ -7,7 +7,7 @@ version = "0.10.0" [dependencies] lazy_static = "1.4.0" -assets_manager = {version = "0.6.0", features = ["bincode", "ron", "json"]} +assets_manager = {version = "0.7", features = ["bincode", "ron", "json"]} ron = { version = "0.7", default-features = false } dot_vox = "4.0" image = { version = "0.23.12", default-features = false, features = ["png"] } diff --git a/common/assets/src/fs.rs b/common/assets/src/fs.rs new file mode 100644 index 0000000000..c789e71013 --- /dev/null +++ b/common/assets/src/fs.rs @@ -0,0 +1,91 @@ +use std::{borrow::Cow, io, path::PathBuf}; + +use assets_manager::{ + hot_reloading::{DynUpdateSender, EventSender, FsWatcherBuilder}, + source::{DirEntry, FileSystem as RawFs, Source}, + BoxedError, +}; + +/// Loads assets from the default path or `VELOREN_ASSETS_OVERRIDE` env if it is +/// set. +#[derive(Debug, Clone)] +pub struct FileSystem { + default: RawFs, + override_dir: Option, +} + +impl FileSystem { + pub fn new() -> io::Result { + let default = RawFs::new(&*super::ASSETS_PATH)?; + let override_dir = std::env::var_os("VELOREN_ASSETS_OVERRIDE").and_then(|path| { + RawFs::new(path) + .map_err(|err| tracing::error!("Error setting override assets directory: {}", err)) + .ok() + }); + + Ok(Self { + default, + override_dir, + }) + } + + pub fn path_of(&self, specifier: &str, ext: &str) -> PathBuf { + self.default.path_of(DirEntry::File(specifier, ext)) + } +} + +impl Source for FileSystem { + fn read(&self, id: &str, ext: &str) -> io::Result> { + if let Some(dir) = &self.override_dir { + match dir.read(id, ext) { + Ok(content) => return Ok(content), + Err(err) => { + if err.kind() != io::ErrorKind::NotFound { + let path = dir.path_of(DirEntry::File(id, ext)); + tracing::warn!("Error reading \"{}\": {}", path.display(), err); + } + }, + } + } + + // If not found in override path, try load from main asset path + self.default.read(id, ext) + } + + fn read_dir(&self, id: &str, f: &mut dyn FnMut(DirEntry)) -> io::Result<()> { + if let Some(dir) = &self.override_dir { + match dir.read_dir(id, f) { + Ok(()) => return Ok(()), + Err(err) => { + if err.kind() != io::ErrorKind::NotFound { + let path = dir.path_of(DirEntry::Directory(id)); + tracing::warn!("Error reading \"{}\": {}", path.display(), err); + } + }, + } + } + + // If not found in override path, try load from main asset path + self.default.read_dir(id, f) + } + + fn exists(&self, entry: DirEntry) -> bool { + self.override_dir + .as_ref() + .map_or(false, |dir| dir.exists(entry)) + || self.default.exists(entry) + } + + fn make_source(&self) -> Option> { Some(Box::new(self.clone())) } + + fn configure_hot_reloading(&self, events: EventSender) -> Result { + let mut builder = FsWatcherBuilder::new()?; + + if let Some(dir) = &self.override_dir { + builder.watch(dir.root().to_owned())?; + } + builder.watch(self.default.root().to_owned())?; + + Ok(builder.build(events)) + } +} diff --git a/common/assets/src/lib.rs b/common/assets/src/lib.rs index b592f40286..62310ba162 100644 --- a/common/assets/src/lib.rs +++ b/common/assets/src/lib.rs @@ -4,7 +4,7 @@ use dot_vox::DotVoxData; use image::DynamicImage; use lazy_static::lazy_static; -use std::{borrow::Cow, fmt, path::PathBuf, sync::Arc}; +use std::{borrow::Cow, path::PathBuf, sync::Arc}; pub use assets_manager::{ asset::{DirLoadable, Ron}, @@ -15,29 +15,21 @@ pub use assets_manager::{ Asset, AssetCache, BoxedError, Compound, Error, SharedString, }; +mod fs; + lazy_static! { /// The HashMap where all loaded assets are stored in. - static ref ASSETS: AssetCache = - AssetCache::new(&*ASSETS_PATH).unwrap(); - /// Asset cache for overrides - static ref ASSETS_OVERRIDE: Option = { - std::env::var("VELOREN_ASSETS_OVERRIDE").ok().map(|path| { - AssetCache::new(path).unwrap() - }) - }; + static ref ASSETS: AssetCache = + AssetCache::with_source(fs::FileSystem::new().unwrap()); } #[cfg(feature = "hot-reloading")] -pub fn start_hot_reloading() { - ASSETS.enhance_hot_reloading(); - if let Some(cache) = &*ASSETS_OVERRIDE { - cache.enhance_hot_reloading(); - } -} +pub fn start_hot_reloading() { ASSETS.enhance_hot_reloading(); } pub type AssetHandle = assets_manager::Handle<'static, T>; pub type AssetGuard = assets_manager::AssetGuard<'static, T>; -pub type AssetDirHandle = assets_manager::DirHandle<'static, T, source::FileSystem>; +pub type AssetDirHandle = assets_manager::DirHandle<'static, T, fs::FileSystem>; +pub type ReloadWatcher = assets_manager::ReloadWatcher<'static>; /// The Asset trait, which is implemented by all structures that have their data /// stored in the filesystem. @@ -76,12 +68,21 @@ pub trait AssetExt: Sized + Send + Sync + 'static { /// ``` #[track_caller] fn load_expect(specifier: &str) -> AssetHandle { - Self::load(specifier).unwrap_or_else(|err| { + #[track_caller] + #[cold] + fn expect_failed(err: Error) -> ! { panic!( "Failed loading essential asset: {} (error={:?})", - specifier, err + err.id(), + err.reason() ) - }) + } + + // Avoid using `unwrap_or_else` to avoid breaking `#[track_caller]` + match Self::load(specifier) { + Ok(handle) => handle, + Err(err) => expect_failed(err), + } } /// Function used to load essential assets from the filesystem or the cache @@ -111,21 +112,8 @@ pub fn load_dir( specifier: &str, recursive: bool, ) -> Result, Error> { - use std::io; - let specifier = specifier.strip_suffix(".*").unwrap_or(specifier); - // Try override path first - let from_override = match &*ASSETS_OVERRIDE { - Some(cache) => cache.load_dir(specifier, recursive), - None => return ASSETS.load_dir(specifier, recursive), - }; - // If not found in override path, try load from main asset path - match from_override { - Err(Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => { - ASSETS.load_dir(specifier, recursive) - }, - _ => from_override, - } + ASSETS.load_dir(specifier, recursive) } /// Loads directory and all files in it @@ -138,88 +126,30 @@ pub fn read_expect_dir( specifier: &str, recursive: bool, ) -> impl Iterator> { - load_dir::(specifier, recursive) - .unwrap_or_else(|e| panic!("Failed loading directory {}. error={:?}", e, specifier)) - .ids() - .map(|entry| T::load_expect(entry).read()) -} + #[track_caller] + #[cold] + fn expect_failed(err: Error) -> ! { + panic!( + "Failed loading directory: {} (error={:?})", + err.id(), + err.reason() + ) + } -#[derive(Debug)] -pub struct AssetError(String, Error); - -impl std::error::Error for AssetError {} -impl fmt::Display for AssetError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Failed to load '{}': {}", self.0, self.1) + // Avoid using `unwrap_or_else` to avoid breaking `#[track_caller]` + match load_dir::(specifier, recursive) { + Ok(dir) => dir.ids().map(|entry| T::load_expect(entry).read()), + Err(err) => expect_failed(err), } } impl AssetExt for T { - fn load(specifier: &str) -> Result, Error> { - use std::io; - // Try override path first - let from_override = match &*ASSETS_OVERRIDE { - Some(cache) => cache.load(specifier), - None => return ASSETS.load(specifier), - }; - // If not found in override path, try load from main asset path - // - // NOTE: this won't work if asset catches error with - // Asset::default_value during Asset::load. - // - // We don't use it, and hopefully won't because there is - // `AssetExt::get_or_insert` or `AssetExt::load_or_insert_with` - // that allows you to do the same. - // - // If accidentaly we end up using Asset::default_value, - // there is possibility of this code trying to load - // from override cache and end there returning default value - // for `cache.load(specifier)` above. - match from_override { - Err(Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => ASSETS.load(specifier), - Err(e) => Err(Error::Conversion(Box::new(AssetError( - specifier.to_string(), - e, - )))), - _ => from_override, - } - } + fn load(specifier: &str) -> Result, Error> { ASSETS.load(specifier) } - fn load_owned(specifier: &str) -> Result { - use std::io; - // Try override path first - let from_override = match &*ASSETS_OVERRIDE { - Some(cache) => cache.load_owned(specifier), - None => return ASSETS.load_owned(specifier), - }; - // If not found in override path, try load from main asset path - match from_override { - Err(Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => { - ASSETS.load_owned(specifier) - }, - _ => from_override, - } - } + fn load_owned(specifier: &str) -> Result { ASSETS.load_owned(specifier) } fn get_or_insert(specifier: &str, default: Self) -> AssetHandle { - // 1) Check if we have ASSETS_OVERRIDE, if not - use main ASSETS - // 2) Check if we have this asset in ASSETS_OVERRIDE, if not - - // use main ASSETS - // 3) If we have this asset in ASSETS_OVERRIDE, use ASSETS_OVERRIDE. - use std::io; - - let override_cache = match &*ASSETS_OVERRIDE { - Some(cache) => cache, - None => return ASSETS.get_or_insert(specifier, default), - }; - let from_override = override_cache.load::(specifier); - // If not found in override path, try load from main asset path - match from_override { - Err(Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => { - ASSETS.get_or_insert(specifier, default) - }, - _ => override_cache.get_or_insert(specifier, default), - } + ASSETS.get_or_insert(specifier, default) } } @@ -355,11 +285,7 @@ lazy_static! { /// Returns the actual path of the specifier with the extension. /// /// For directories, give `""` as extension. -pub fn path_of(specifier: &str, ext: &str) -> PathBuf { - ASSETS - .source() - .path_of(source::DirEntry::File(specifier, ext)) -} +pub fn path_of(specifier: &str, ext: &str) -> PathBuf { ASSETS.source().path_of(specifier, ext) } #[cfg(test)] mod tests { @@ -481,7 +407,7 @@ pub mod asset_tweak { Specifier::Asset(path) => path.join("."), }; let handle = as AssetExt>::load_expect(&asset_specifier); - let AssetTweakWrapper(value) = handle.read().clone(); + let AssetTweakWrapper(value) = handle.cloned(); value } diff --git a/common/src/bin/csv_import/main.rs b/common/src/bin/csv_import/main.rs index 34b0077209..7c70a0de61 100644 --- a/common/src/bin/csv_import/main.rs +++ b/common/src/bin/csv_import/main.rs @@ -226,10 +226,10 @@ fn armor_stats() -> Result<(), Box> { ); let pretty_config = PrettyConfig::new() - .with_depth_limit(4) - .with_separate_tuple_members(true) - .with_decimal_floats(true) - .with_enumerate_arrays(true); + .depth_limit(4) + .separate_tuple_members(true) + .decimal_floats(true) + .enumerate_arrays(true); let mut path = ASSETS_PATH.clone(); for part in item.item_definition_id().split('.') { @@ -418,10 +418,10 @@ fn weapon_stats() -> Result<(), Box> { ); let pretty_config = PrettyConfig::new() - .with_depth_limit(4) - .with_separate_tuple_members(true) - .with_decimal_floats(true) - .with_enumerate_arrays(true); + .depth_limit(4) + .separate_tuple_members(true) + .decimal_floats(true) + .enumerate_arrays(true); let mut path = ASSETS_PATH.clone(); for part in item.item_definition_id().split('.') { @@ -494,9 +494,7 @@ fn loot_table(loot_table: &str) -> Result<(), Box> { items.push((chance, item)); } - let pretty_config = PrettyConfig::new() - .with_depth_limit(4) - .with_decimal_floats(true); + let pretty_config = PrettyConfig::new().depth_limit(4).decimal_floats(true); let mut path = ASSETS_PATH.clone(); path.push("common"); diff --git a/common/src/comp/body/ship.rs b/common/src/comp/body/ship.rs index 0b429d3bc2..ca3175aeec 100644 --- a/common/src/comp/body/ship.rs +++ b/common/src/comp/body/ship.rs @@ -197,10 +197,10 @@ pub mod figuredata { } impl assets::Compound for ShipSpec { - fn load( + fn load( cache: &assets::AssetCache, _: &str, - ) -> Result { + ) -> Result { let manifest: AssetHandle> = AssetExt::load("common.manifests.ship_manifest")?; let mut colliders = HashMap::new(); diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index 879ce604ee..51b17796b9 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -7,7 +7,7 @@ pub use modular::{ModularComponent, ModularComponentKind, ModularComponentTag}; pub use tool::{AbilitySet, AbilitySpec, Hands, MaterialStatManifest, Tool, ToolKind}; use crate::{ - assets::{self, AssetExt, Error}, + assets::{self, AssetExt, BoxedError, Error}, comp::inventory::{item::tool::AbilityMap, InvSlot}, effect::Effect, recipe::RecipeInput, @@ -550,10 +550,10 @@ impl Deref for Item { } impl assets::Compound for ItemDef { - fn load( + fn load( cache: &assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { // load from the filesystem first, but if the file doesn't exist, see if it's a // programmaticly-generated asset let raw = match cache.load::(specifier) { diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 9a287850f5..fcb54deb7a 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -432,10 +432,10 @@ impl Asset for AbilityMap { } impl assets::Compound for AbilityMap { - fn load( + fn load( cache: &assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { let manifest = cache.load::>(specifier)?.read(); Ok(AbilityMap( diff --git a/common/src/comp/inventory/loadout_builder.rs b/common/src/comp/inventory/loadout_builder.rs index 61adfa02f4..2619eea576 100644 --- a/common/src/comp/inventory/loadout_builder.rs +++ b/common/src/comp/inventory/loadout_builder.rs @@ -502,7 +502,7 @@ impl LoadoutBuilder { /// 3) Will panic while runs in tests and asset doesn't have "correct" form #[must_use = "Method consumes builder and returns updated builder."] pub fn with_asset_expect(mut self, asset_specifier: &str, rng: &mut impl Rng) -> Self { - let spec = LoadoutSpec::load_expect(asset_specifier).read().0.clone(); + let spec = LoadoutSpec::load_expect_cloned(asset_specifier).0; for (key, entry) in spec { let item = match entry.try_to_item(asset_specifier, rng) { Some(item) => item, diff --git a/common/src/comp/inventory/trade_pricing.rs b/common/src/comp/inventory/trade_pricing.rs index 8a4bf32493..70a195d08d 100644 --- a/common/src/comp/inventory/trade_pricing.rs +++ b/common/src/comp/inventory/trade_pricing.rs @@ -151,10 +151,10 @@ impl EqualitySet { } impl assets::Compound for EqualitySet { - fn load( + fn load( cache: &assets::AssetCache, id: &str, - ) -> Result { + ) -> Result { #[derive(Debug, Deserialize)] enum EqualitySpec { LootTable(String), diff --git a/common/src/generation.rs b/common/src/generation.rs index 67b9ee84cf..cfc4969157 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -202,7 +202,7 @@ impl EntityInfo { /// Helper function for applying config from asset pub fn with_asset_expect(self, asset_specifier: &str) -> Self { - let config = EntityConfig::load_expect(asset_specifier).read().clone(); + let config = EntityConfig::load_expect_cloned(asset_specifier); self.with_entity_config(config, Some(asset_specifier)) } diff --git a/common/src/recipe.rs b/common/src/recipe.rs index 0bdb9ac1fa..5fe7ec4a24 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -234,10 +234,10 @@ impl assets::Asset for RawRecipeBook { } impl assets::Compound for RecipeBook { - fn load( + fn load( cache: &assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { #[inline] fn load_item_def(spec: &(String, u32)) -> Result<(Arc, u32), assets::Error> { let def = Arc::::load_cloned(&spec.0)?; @@ -255,7 +255,7 @@ impl assets::Compound for RecipeBook { Ok((def, spec.1)) } - let mut raw = cache.load::(specifier)?.read().clone(); + let mut raw = cache.load::(specifier)?.cloned(); // Avoid showing purple-question-box recipes until the assets are added // (the `if false` is needed because commenting out the call will add a warning diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index 48edef66dc..21bbbfe91f 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -1,6 +1,6 @@ use super::{BlockKind, SpriteKind}; use crate::{ - assets::{self, AssetExt, AssetHandle, DotVoxAsset, Error}, + assets::{self, AssetExt, AssetHandle, BoxedError, DotVoxAsset}, make_case_elim, vol::{BaseVol, ReadVol, SizedVol, WriteVol}, volumes::dyna::{Dyna, DynaError}, @@ -67,10 +67,10 @@ impl std::ops::Deref for StructuresGroup { } impl assets::Compound for StructuresGroup { - fn load( + fn load( cache: &assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { let specs = cache.load::(specifier)?.read(); Ok(StructuresGroup( @@ -94,7 +94,7 @@ impl assets::Compound for StructuresGroup { }, }) }) - .collect::>()?, + .collect::>()?, )) } } @@ -137,10 +137,10 @@ impl ReadVol for Structure { } impl assets::Compound for BaseStructure { - fn load( + fn load( cache: &assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { let dot_vox_data = cache.load::(specifier)?.read(); let dot_vox_data = &dot_vox_data.0; diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 8439a3a754..d32f38d4fa 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -89,6 +89,7 @@ gilrs = {version = "0.8.0", features = ["serde-serialize"]} server = { package = "veloren-server", path = "../server", optional = true, default-features = false, features = ["worldgen"] } # Utility +assets_manager = {version = "0.7", features = ["ab_glyph"]} backtrace = "0.3.40" bincode = "1.3.1" chrono = { version = "0.4.19", features = ["serde"] } diff --git a/voxygen/i18n/src/lib.rs b/voxygen/i18n/src/lib.rs index 27a2191073..428e867078 100644 --- a/voxygen/i18n/src/lib.rs +++ b/voxygen/i18n/src/lib.rs @@ -11,7 +11,7 @@ pub mod verification; pub use path::BasePath; use crate::path::{LANG_EXTENSION, LANG_MANIFEST_FILE}; -use common_assets::{self, source::DirEntry, AssetExt, AssetGuard, AssetHandle}; +use common_assets::{self, source::DirEntry, AssetExt, AssetGuard, AssetHandle, ReloadWatcher}; use hashbrown::{HashMap, HashSet}; use raw::{RawFragment, RawLanguage, RawManifest}; use serde::{Deserialize, Serialize}; @@ -102,10 +102,10 @@ impl Language { } impl common_assets::Compound for Language { - fn load( + fn load( cache: &common_assets::AssetCache, asset_key: &str, - ) -> Result { + ) -> Result { let manifest = cache .load::(&[asset_key, ".", LANG_MANIFEST_FILE].concat())? .cloned(); @@ -145,9 +145,10 @@ impl common_assets::Compound for Language { /// the central data structure to handle localization in veloren // inherit Copy+Clone from AssetHandle -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct LocalizationHandle { active: AssetHandle, + watcher: ReloadWatcher, fallback: Option>, pub use_english_fallback: bool, } @@ -259,8 +260,10 @@ impl LocalizationHandle { let default_key = ["voxygen.i18n.", REFERENCE_LANG].concat(); let language_key = ["voxygen.i18n.", specifier].concat(); let is_default = language_key == default_key; + let active = Language::load(&language_key)?; Ok(Self { - active: Language::load(&language_key)?, + active, + watcher: active.reload_watcher(), fallback: if is_default { None } else { @@ -274,16 +277,16 @@ impl LocalizationHandle { Self::load(specifier).expect("Can't load language files") } - pub fn reloaded(&mut self) -> bool { self.active.reloaded() } + pub fn reloaded(&mut self) -> bool { self.watcher.reloaded() } } struct FindManifests; impl common_assets::Compound for FindManifests { - fn load( + fn load( _: &common_assets::AssetCache, _: &str, - ) -> Result { + ) -> Result { Ok(Self) } } @@ -312,10 +315,10 @@ impl common_assets::DirLoadable for FindManifests { struct LocalizationList(Vec); impl common_assets::Compound for LocalizationList { - fn load( + fn load( cache: &common_assets::AssetCache, specifier: &str, - ) -> Result { + ) -> Result { // List language directories let languages = common_assets::load_dir::(specifier, false) .unwrap_or_else(|e| panic!("Failed to get manifests from {}: {:?}", specifier, e)) diff --git a/voxygen/i18n/src/raw.rs b/voxygen/i18n/src/raw.rs index 56e4e4b1c7..da814bfc1f 100644 --- a/voxygen/i18n/src/raw.rs +++ b/voxygen/i18n/src/raw.rs @@ -31,16 +31,11 @@ pub(crate) struct RawLanguage { pub(crate) fragments: HashMap>, } -#[derive(Debug)] -pub(crate) enum RawError { - RonError(ron::Error), -} - -pub(crate) fn load_manifest(path: &LangPath) -> Result { +pub(crate) fn load_manifest(path: &LangPath) -> Result { let manifest_file = path.file(LANG_MANIFEST_FILE); tracing::debug!(?manifest_file, "manifest loading"); let f = fs::File::open(&manifest_file)?; - let manifest: RawManifest = from_reader(f).map_err(RawError::RonError)?; + let manifest: RawManifest = from_reader(f)?; // verify that the folder name `de_DE` matches the value inside the metadata! assert_eq!( manifest.metadata.language_identifier, @@ -52,7 +47,7 @@ pub(crate) fn load_manifest(path: &LangPath) -> Result Result, common_assets::Error> { +) -> Result, common_assets::BoxedError> { //get List of files let files = path.fragments()?; @@ -60,7 +55,7 @@ pub(crate) fn load_raw_language( let mut fragments = HashMap::new(); for sub_path in files { let f = fs::File::open(path.sub_path(&sub_path))?; - let fragment = from_reader(f).map_err(RawError::RonError)?; + let fragment = from_reader(f)?; fragments.insert(sub_path, fragment); } @@ -105,20 +100,6 @@ impl From> for Language { } } -impl core::fmt::Display for RawError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - RawError::RonError(e) => write!(f, "{}", e), - } - } -} - -impl std::error::Error for RawError {} - -impl From for common_assets::Error { - fn from(e: RawError) -> Self { Self::Conversion(Box::new(e)) } -} - impl common_assets::Asset for RawManifest { type Loader = common_assets::RonLoader; diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 573310a983..34ee4e9825 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -420,10 +420,10 @@ impl assets::Asset for SoundtrackCollection { } impl assets::Compound for SoundtrackCollection { - fn load( + fn load( _: &assets::AssetCache, id: &str, - ) -> Result { + ) -> Result { let inner = || -> Result<_, assets::Error> { let manifest: AssetHandle> = AssetExt::load(id)?; diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 0bb5d4410f..0d39f9d2ed 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -1,6 +1,6 @@ use crate::ui::{Graphic, SampleStrat, Transform, Ui}; use common::{ - assets::{self, AssetExt, AssetHandle, DotVoxAsset}, + assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher}, comp::item::{ armor::{Armor, ArmorKind}, Glider, ItemDef, ItemDesc, ItemKind, Lantern, Throwable, Utility, @@ -109,6 +109,7 @@ impl assets::Asset for ItemImagesSpec { pub struct ItemImgs { map: HashMap, manifest: AssetHandle, + watcher: ReloadWatcher, not_found: Id, } @@ -128,6 +129,7 @@ impl ItemImgs { Self { map, manifest, + watcher: manifest.reload_watcher(), not_found, } } @@ -135,7 +137,7 @@ impl ItemImgs { /// Checks if the manifest has been changed and reloads the images if so /// Reuses img ids pub fn reload_if_changed(&mut self, ui: &mut Ui) { - if self.manifest.reloaded() { + if self.watcher.reloaded() { for (kind, spec) in self.manifest.read().0.iter() { // Load new graphic let graphic = spec.create_graphic(); diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 1c5f22bd57..62b929d6b5 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -28,7 +28,7 @@ use super::{ AaMode, AddressMode, FilterMode, OtherModes, PipelineModes, RenderError, RenderMode, ShadowMapMode, ShadowMode, Vertex, }; -use common::assets::{self, AssetExt, AssetHandle}; +use common::assets::{self, AssetExt, AssetHandle, ReloadWatcher}; use common_base::span; use core::convert::TryFrom; #[cfg(feature = "egui-ui")] @@ -157,6 +157,7 @@ pub struct Renderer { quad_index_buffer_u32: Buffer, shaders: AssetHandle, + shaders_watcher: ReloadWatcher, pipeline_modes: PipelineModes, other_modes: OtherModes, @@ -360,6 +361,7 @@ impl Renderer { .ok(); let shaders = Shaders::load_expect(""); + let shaders_watcher = shaders.reload_watcher(); let layouts = { let global = GlobalsLayouts::new(&device); @@ -407,7 +409,7 @@ impl Renderer { immutable: Arc::clone(&layouts.immutable), postprocess: Arc::clone(&layouts.postprocess), }, - shaders.read().clone(), + shaders.cloned(), pipeline_modes.clone(), sc_desc.clone(), // Note: cheap clone shadow_views.is_some(), @@ -510,6 +512,7 @@ impl Renderer { quad_index_buffer_u32, shaders, + shaders_watcher, pipeline_modes, other_modes, @@ -1053,7 +1056,7 @@ impl Renderer { } // If the shaders files were changed attempt to recreate the shaders - if self.shaders.reloaded() { + if self.shaders_watcher.reloaded() { self.recreate_pipelines(self.pipeline_modes.clone()); } @@ -1113,7 +1116,7 @@ impl Renderer { pipeline_creation::recreate_pipelines( Arc::clone(&self.device), Arc::clone(&self.layouts.immutable), - self.shaders.read().clone(), + self.shaders.cloned(), pipeline_modes, // NOTE: if present_mode starts to be used to configure pipelines then it // needs to become a part of the pipeline modes diff --git a/voxygen/src/render/renderer/shaders.rs b/voxygen/src/render/renderer/shaders.rs index 2d8f32556c..3bcf92cf55 100644 --- a/voxygen/src/render/renderer/shaders.rs +++ b/voxygen/src/render/renderer/shaders.rs @@ -24,10 +24,10 @@ pub struct Shaders { impl assets::Compound for Shaders { // TODO: Taking the specifier argument as a base for shaders specifiers // would allow to use several shaders groups easily - fn load( + fn load( _: &assets::AssetCache, _: &str, - ) -> Result { + ) -> Result { let shaders = [ "include.constants", "include.globals", diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index ca35f63874..fd3f36aaf5 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -6,6 +6,7 @@ use crate::{ }; use anim::Skeleton; use common::{ + assets::ReloadWatcher, comp::{ inventory::{ slot::{ArmorSlot, EquipSlot}, @@ -287,6 +288,7 @@ where { models: HashMap, ((FigureModelEntryFuture, Skel::Attr), u64)>, manifests: ::Manifests, + watcher: ReloadWatcher, } impl FigureModelCache @@ -295,10 +297,14 @@ where { #[allow(clippy::new_without_default)] // TODO: Pending review in #587 pub fn new() -> Self { + // NOTE: It might be better to bubble this error up rather than panicking. + let manifests = ::load_spec().unwrap(); + let watcher = ::reload_watcher(&manifests); + Self { models: HashMap::new(), - // NOTE: It might be better to bubble this error up rather than panicking. - manifests: ::load_spec().unwrap(), + manifests, + watcher, } } @@ -561,7 +567,7 @@ where { // Check for reloaded manifests // TODO: maybe do this in a different function, maintain? - if ::is_reloaded(&mut self.manifests) { + if self.watcher.reloaded() { col_lights.atlas.clear(); self.models.clear(); } diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 7da8c90bb7..084eb5b301 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -1,6 +1,6 @@ use super::cache::{FigureKey, ToolKey}; use common::{ - assets::{self, AssetExt, AssetHandle, DotVoxAsset, Ron}, + assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher, Ron}, comp::{ biped_large::{self, BodyType as BLBodyType, Species as BLSpecies}, biped_small, @@ -96,7 +96,7 @@ pub trait BodySpec: Sized { fn load_spec() -> Result; /// Determine whether the cache's manifest was reloaded - fn is_reloaded(manifests: &mut Self::Manifests) -> bool; + fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher; /// Mesh bones using the given spec, character state, and mesh generation /// function. @@ -124,7 +124,7 @@ macro_rules! make_vox_spec { } impl assets::Compound for $Spec { - fn load(_: &assets::AssetCache, _: &str) -> Result { + fn load(_: &assets::AssetCache, _: &str) -> Result { Ok($Spec { $( $field: AssetExt::load($asset_path)?, )* }) @@ -141,7 +141,7 @@ macro_rules! make_vox_spec { Self::Spec::load("") } - fn is_reloaded(manifests: &mut Self::Manifests) -> bool { manifests.reloaded() } + fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() } fn bone_meshes( $self_pat: &FigureKey, @@ -4549,7 +4549,7 @@ impl BodySpec for ship::Body { #[allow(unused_variables)] fn load_spec() -> Result { Self::Spec::load("") } - fn is_reloaded(manifests: &mut Self::Manifests) -> bool { manifests.reloaded() } + fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() } fn bone_meshes( FigureKey { body, .. }: &FigureKey, diff --git a/voxygen/src/scene/figure/volume.rs b/voxygen/src/scene/figure/volume.rs index 9f4664c80c..15915e3063 100644 --- a/voxygen/src/scene/figure/volume.rs +++ b/voxygen/src/scene/figure/volume.rs @@ -61,7 +61,9 @@ impl BodySpec for VolumeKey { fn load_spec() -> Result { Ok(()) } - fn is_reloaded(_: &mut Self::Manifests) -> bool { false } + fn reload_watcher(_: &Self::Manifests) -> assets::ReloadWatcher { + assets::ReloadWatcher::default() + } fn bone_meshes( _: &FigureKey, diff --git a/voxygen/src/ui/ice/cache.rs b/voxygen/src/ui/ice/cache.rs index e7631e10a4..00ecbe1e15 100644 --- a/voxygen/src/ui/ice/cache.rs +++ b/voxygen/src/ui/ice/cache.rs @@ -5,10 +5,7 @@ use crate::{ }; use common::assets::{self, AssetExt}; use glyph_brush::GlyphBrushBuilder; -use std::{ - borrow::Cow, - cell::{RefCell, RefMut}, -}; +use std::cell::{RefCell, RefMut}; use vek::*; // Multiplied by current window size @@ -24,22 +21,7 @@ type GlyphBrush = glyph_brush::GlyphBrush<(Aabr, Aabr), ()>; // TODO: might not need pub pub type Font = glyph_brush::ab_glyph::FontArc; -struct FontAsset(Font); -struct FontLoader; -impl assets::Loader for FontLoader { - fn load(data: Cow<[u8]>, _: &str) -> Result { - let font = Font::try_from_vec(data.into_owned())?; - Ok(FontAsset(font)) - } -} - -impl assets::Asset for FontAsset { - type Loader = FontLoader; - - const EXTENSION: &'static str = "ttf"; -} - -pub fn load_font(specifier: &str) -> Font { FontAsset::load_expect(specifier).read().0.clone() } +pub fn load_font(specifier: &str) -> Font { Font::load_expect(specifier).cloned() } #[derive(Clone, Copy, Default)] pub struct FontId(pub(super) glyph_brush::FontId); diff --git a/world/src/layer/wildlife.rs b/world/src/layer/wildlife.rs index ebb9c74ef6..72eca50d5d 100644 --- a/world/src/layer/wildlife.rs +++ b/world/src/layer/wildlife.rs @@ -38,7 +38,7 @@ impl assets::Asset for SpawnEntry { } impl SpawnEntry { - pub fn from(asset_specifier: &str) -> Self { Self::load_expect(asset_specifier).read().clone() } + pub fn from(asset_specifier: &str) -> Self { Self::load_expect_cloned(asset_specifier) } pub fn request(&self, requested_period: DayPeriod, underwater: bool) -> Option { self.rules diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index e92438604b..1aba30c493 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -442,18 +442,17 @@ impl WorldSim { FileOpts::LoadAsset(ref specifier) => match WorldFile::load_owned(specifier) { Ok(map) => map.into_modern(), Err(err) => { - match err { - assets::Error::Io(e) => { + match err.reason().downcast_ref::() { + Some(e) => { warn!(?e, ?specifier, "Couldn't read asset specifier for maps"); }, - assets::Error::Conversion(e) => { + None => { warn!( - ?e, + ?err, "Couldn't parse modern map. Maybe you meant to try a legacy \ load?" ); }, - assets::Error::NoDefaultValue => unreachable!(), } return None; }, From 287896facdbdc52314f264a86f71fbfe1acf1544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 13 Dec 2021 18:17:23 +0100 Subject: [PATCH 2/3] Remove common_assets::path_of` --- common/assets/src/fs.rs | 6 +----- common/assets/src/lib.rs | 5 ----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/common/assets/src/fs.rs b/common/assets/src/fs.rs index c789e71013..8ce6d39787 100644 --- a/common/assets/src/fs.rs +++ b/common/assets/src/fs.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, io, path::PathBuf}; +use std::{borrow::Cow, io}; use assets_manager::{ hot_reloading::{DynUpdateSender, EventSender, FsWatcherBuilder}, @@ -28,10 +28,6 @@ impl FileSystem { override_dir, }) } - - pub fn path_of(&self, specifier: &str, ext: &str) -> PathBuf { - self.default.path_of(DirEntry::File(specifier, ext)) - } } impl Source for FileSystem { diff --git a/common/assets/src/lib.rs b/common/assets/src/lib.rs index 62310ba162..4801a8c84c 100644 --- a/common/assets/src/lib.rs +++ b/common/assets/src/lib.rs @@ -282,11 +282,6 @@ lazy_static! { }; } -/// Returns the actual path of the specifier with the extension. -/// -/// For directories, give `""` as extension. -pub fn path_of(specifier: &str, ext: &str) -> PathBuf { ASSETS.source().path_of(specifier, ext) } - #[cfg(test)] mod tests { use std::{ffi::OsStr, fs::File}; From 8cf871f449ee63fce2965e4796b256fcacccb709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 13 Dec 2021 18:52:13 +0100 Subject: [PATCH 3/3] Edit log message as suggested --- common/assets/src/fs.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/common/assets/src/fs.rs b/common/assets/src/fs.rs index 8ce6d39787..7a3662d76f 100644 --- a/common/assets/src/fs.rs +++ b/common/assets/src/fs.rs @@ -38,7 +38,11 @@ impl Source for FileSystem { Err(err) => { if err.kind() != io::ErrorKind::NotFound { let path = dir.path_of(DirEntry::File(id, ext)); - tracing::warn!("Error reading \"{}\": {}", path.display(), err); + tracing::warn!( + "Error reading \"{}\": {}. Falling back to default", + path.display(), + err + ); } }, } @@ -55,7 +59,11 @@ impl Source for FileSystem { Err(err) => { if err.kind() != io::ErrorKind::NotFound { let path = dir.path_of(DirEntry::Directory(id)); - tracing::warn!("Error reading \"{}\": {}", path.display(), err); + tracing::warn!( + "Error reading \"{}\": {}. Falling back to default", + path.display(), + err + ); } }, }