Add support for override asset folder

- ASSETS_OVERRIDE environment variable with asset path which has higher
  priority.
This commit is contained in:
juliancoffee 2021-09-02 12:26:36 +03:00
parent 970d57f905
commit 6c1ecc9766
3 changed files with 85 additions and 11 deletions

View File

@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Chestnut and cedar tree varieties - Chestnut and cedar tree varieties
- Shooting sprites, such as apples and hives, can knock them out of trees - Shooting sprites, such as apples and hives, can knock them out of trees
- Sprite pickup animations - Sprite pickup animations
- Add VELOREN_ASSETS_OVERRIDE variable for specifying folder to partially override assets.
### Changed ### Changed

View File

@ -19,10 +19,21 @@ lazy_static! {
/// The HashMap where all loaded assets are stored in. /// The HashMap where all loaded assets are stored in.
static ref ASSETS: AssetCache = static ref ASSETS: AssetCache =
AssetCache::new(&*ASSETS_PATH).unwrap(); AssetCache::new(&*ASSETS_PATH).unwrap();
/// Asset cache for overrides
static ref ASSETS_OVERRIDE: Option<AssetCache> = {
std::env::var("VELOREN_ASSETS_OVERRIDE").ok().map(|path| {
AssetCache::new(path).unwrap()
})
};
} }
#[cfg(feature = "hot-reloading")] #[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<T> = assets_manager::Handle<'static, T>; pub type AssetHandle<T> = assets_manager::Handle<'static, T>;
pub type AssetGuard<T> = assets_manager::AssetGuard<'static, T>; pub type AssetGuard<T> = assets_manager::AssetGuard<'static, T>;
@ -104,8 +115,21 @@ pub fn load_dir<T: DirLoadable>(
specifier: &str, specifier: &str,
recursive: bool, recursive: bool,
) -> Result<AssetDirHandle<T>, Error> { ) -> Result<AssetDirHandle<T>, Error> {
use std::io;
let specifier = specifier.strip_suffix(".*").unwrap_or(specifier); 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 /// Loads directory and all files in it
@ -125,12 +149,67 @@ pub fn read_expect_dir<T: DirLoadable>(
} }
impl<T: Compound> AssetExt for T { impl<T: Compound> AssetExt for T {
fn load(specifier: &str) -> Result<AssetHandle<Self>, Error> { ASSETS.load(specifier) } fn load(specifier: &str) -> Result<AssetHandle<Self>, 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<Self, Error> { ASSETS.load_owned(specifier) } fn load_owned(specifier: &str) -> Result<Self, Error> {
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<Self> { fn get_or_insert(specifier: &str, default: Self) -> AssetHandle<Self> {
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::<T>(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),
}
} }
} }

View File

@ -23,12 +23,6 @@ impl assets::Asset for OggSound {
type Loader = SoundLoader; type Loader = SoundLoader;
const EXTENSION: &'static str = "ogg"; const EXTENSION: &'static str = "ogg";
fn default_value(specifier: &str, error: assets::Error) -> Result<Self, assets::Error> {
warn!(?specifier, ?error, "Failed to load sound");
Ok(OggSound::empty())
}
} }
/// Wrapper for decoded audio data /// Wrapper for decoded audio data