From 6c1ecc97661a9e0aa0b4164ae4374901988a7cc1 Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Thu, 2 Sep 2021 12:26:36 +0300 Subject: [PATCH] Add support for override asset folder - ASSETS_OVERRIDE environment variable with asset path which has higher priority. --- CHANGELOG.md | 1 + common/assets/src/lib.rs | 89 +++++++++++++++++++++++++++++++-- voxygen/src/audio/soundcache.rs | 6 --- 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7214e8592..dfa1c14199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Chestnut and cedar tree varieties - Shooting sprites, such as apples and hives, can knock them out of trees - Sprite pickup animations +- Add VELOREN_ASSETS_OVERRIDE variable for specifying folder to partially override assets. ### Changed diff --git a/common/assets/src/lib.rs b/common/assets/src/lib.rs index fb21436cfa..9786ce8aa6 100644 --- a/common/assets/src/lib.rs +++ b/common/assets/src/lib.rs @@ -19,10 +19,21 @@ 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() + }) + }; } #[cfg(feature = "hot-reloading")] -pub fn start_hot_reloading() { ASSETS.enhance_hot_reloading(); } +pub fn start_hot_reloading() { + ASSETS.enhance_hot_reloading(); + if let Some(cache) = &*ASSETS_OVERRIDE { + cache.enhance_hot_reloading(); + } +} pub type AssetHandle = assets_manager::Handle<'static, T>; pub type AssetGuard = assets_manager::AssetGuard<'static, T>; @@ -104,8 +115,21 @@ pub fn load_dir( specifier: &str, recursive: bool, ) -> Result, Error> { + use std::io; + let specifier = specifier.strip_suffix(".*").unwrap_or(specifier); - ASSETS.load_dir(specifier, recursive) + // 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, + } } /// Loads directory and all files in it @@ -125,12 +149,67 @@ pub fn read_expect_dir( } impl AssetExt for T { - fn load(specifier: &str) -> Result, Error> { ASSETS.load(specifier) } + 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), + _ => from_override, + } + } - fn load_owned(specifier: &str) -> Result { ASSETS.load_owned(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 get_or_insert(specifier: &str, default: Self) -> AssetHandle { - ASSETS.get_or_insert(specifier, default) + // 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), + } } } diff --git a/voxygen/src/audio/soundcache.rs b/voxygen/src/audio/soundcache.rs index 76b6ec2dcd..721bb8c665 100644 --- a/voxygen/src/audio/soundcache.rs +++ b/voxygen/src/audio/soundcache.rs @@ -23,12 +23,6 @@ impl assets::Asset for OggSound { type Loader = SoundLoader; const EXTENSION: &'static str = "ogg"; - - fn default_value(specifier: &str, error: assets::Error) -> Result { - warn!(?specifier, ?error, "Failed to load sound"); - - Ok(OggSound::empty()) - } } /// Wrapper for decoded audio data