mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Update assets_manager
to 0.7
This commit is contained in:
parent
182d5cf971
commit
aca088388b
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -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",
|
||||
|
@ -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 }
|
||||
|
@ -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"] }
|
||||
|
91
common/assets/src/fs.rs
Normal file
91
common/assets/src/fs.rs
Normal file
@ -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<RawFs>,
|
||||
}
|
||||
|
||||
impl FileSystem {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
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<Cow<[u8]>> {
|
||||
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<Box<dyn Source + Send>> { Some(Box::new(self.clone())) }
|
||||
|
||||
fn configure_hot_reloading(&self, events: EventSender) -> Result<DynUpdateSender, BoxedError> {
|
||||
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))
|
||||
}
|
||||
}
|
@ -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<AssetCache> = {
|
||||
std::env::var("VELOREN_ASSETS_OVERRIDE").ok().map(|path| {
|
||||
AssetCache::new(path).unwrap()
|
||||
})
|
||||
};
|
||||
static ref ASSETS: AssetCache<fs::FileSystem> =
|
||||
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<T> = assets_manager::Handle<'static, T>;
|
||||
pub type AssetGuard<T> = assets_manager::AssetGuard<'static, T>;
|
||||
pub type AssetDirHandle<T> = assets_manager::DirHandle<'static, T, source::FileSystem>;
|
||||
pub type AssetDirHandle<T> = 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> {
|
||||
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<T: DirLoadable>(
|
||||
specifier: &str,
|
||||
recursive: bool,
|
||||
) -> Result<AssetDirHandle<T>, 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<T: DirLoadable>(
|
||||
specifier: &str,
|
||||
recursive: bool,
|
||||
) -> impl Iterator<Item = AssetGuard<T>> {
|
||||
load_dir::<T>(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::<T>(specifier, recursive) {
|
||||
Ok(dir) => dir.ids().map(|entry| T::load_expect(entry).read()),
|
||||
Err(err) => expect_failed(err),
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Compound> AssetExt for T {
|
||||
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),
|
||||
Err(e) => Err(Error::Conversion(Box::new(AssetError(
|
||||
specifier.to_string(),
|
||||
e,
|
||||
)))),
|
||||
_ => from_override,
|
||||
}
|
||||
}
|
||||
fn load(specifier: &str) -> Result<AssetHandle<Self>, Error> { ASSETS.load(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 load_owned(specifier: &str) -> Result<Self, Error> { ASSETS.load_owned(specifier) }
|
||||
|
||||
fn get_or_insert(specifier: &str, default: Self) -> AssetHandle<Self> {
|
||||
// 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),
|
||||
}
|
||||
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 = <AssetTweakWrapper<T> as AssetExt>::load_expect(&asset_specifier);
|
||||
let AssetTweakWrapper(value) = handle.read().clone();
|
||||
let AssetTweakWrapper(value) = handle.cloned();
|
||||
|
||||
value
|
||||
}
|
||||
|
@ -226,10 +226,10 @@ fn armor_stats() -> Result<(), Box<dyn Error>> {
|
||||
);
|
||||
|
||||
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<dyn Error>> {
|
||||
);
|
||||
|
||||
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<dyn Error>> {
|
||||
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");
|
||||
|
@ -197,10 +197,10 @@ pub mod figuredata {
|
||||
}
|
||||
|
||||
impl assets::Compound for ShipSpec {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
_: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
let manifest: AssetHandle<Ron<ShipCentralSpec>> =
|
||||
AssetExt::load("common.manifests.ship_manifest")?;
|
||||
let mut colliders = HashMap::new();
|
||||
|
@ -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<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self, BoxedError> {
|
||||
// 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::<RawItemDef>(specifier) {
|
||||
|
@ -432,10 +432,10 @@ impl Asset for AbilityMap<String> {
|
||||
}
|
||||
|
||||
impl assets::Compound for AbilityMap {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
let manifest = cache.load::<AbilityMap<String>>(specifier)?.read();
|
||||
|
||||
Ok(AbilityMap(
|
||||
|
@ -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,
|
||||
|
@ -151,10 +151,10 @@ impl EqualitySet {
|
||||
}
|
||||
|
||||
impl assets::Compound for EqualitySet {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
id: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum EqualitySpec {
|
||||
LootTable(String),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -234,10 +234,10 @@ impl assets::Asset for RawRecipeBook {
|
||||
}
|
||||
|
||||
impl assets::Compound for RecipeBook {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
#[inline]
|
||||
fn load_item_def(spec: &(String, u32)) -> Result<(Arc<ItemDef>, u32), assets::Error> {
|
||||
let def = Arc::<ItemDef>::load_cloned(&spec.0)?;
|
||||
@ -255,7 +255,7 @@ impl assets::Compound for RecipeBook {
|
||||
Ok((def, spec.1))
|
||||
}
|
||||
|
||||
let mut raw = cache.load::<RawRecipeBook>(specifier)?.read().clone();
|
||||
let mut raw = cache.load::<RawRecipeBook>(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
|
||||
|
@ -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<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self, BoxedError> {
|
||||
let specs = cache.load::<StructuresGroupSpec>(specifier)?.read();
|
||||
|
||||
Ok(StructuresGroup(
|
||||
@ -94,7 +94,7 @@ impl assets::Compound for StructuresGroup {
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, Error>>()?,
|
||||
.collect::<Result<_, BoxedError>>()?,
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -137,10 +137,10 @@ impl ReadVol for Structure {
|
||||
}
|
||||
|
||||
impl assets::Compound for BaseStructure {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self, BoxedError> {
|
||||
let dot_vox_data = cache.load::<DotVoxAsset>(specifier)?.read();
|
||||
let dot_vox_data = &dot_vox_data.0;
|
||||
|
||||
|
@ -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"] }
|
||||
|
@ -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<S: common_assets::source::Source>(
|
||||
fn load<S: common_assets::source::Source + ?Sized>(
|
||||
cache: &common_assets::AssetCache<S>,
|
||||
asset_key: &str,
|
||||
) -> Result<Self, common_assets::Error> {
|
||||
) -> Result<Self, common_assets::BoxedError> {
|
||||
let manifest = cache
|
||||
.load::<RawManifest>(&[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<Language>,
|
||||
watcher: ReloadWatcher,
|
||||
fallback: Option<AssetHandle<Language>>,
|
||||
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<S: common_assets::Source>(
|
||||
fn load<S: common_assets::Source + ?Sized>(
|
||||
_: &common_assets::AssetCache<S>,
|
||||
_: &str,
|
||||
) -> Result<Self, common_assets::Error> {
|
||||
) -> Result<Self, common_assets::BoxedError> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
@ -312,10 +315,10 @@ impl common_assets::DirLoadable for FindManifests {
|
||||
struct LocalizationList(Vec<LanguageMetadata>);
|
||||
|
||||
impl common_assets::Compound for LocalizationList {
|
||||
fn load<S: common_assets::Source>(
|
||||
fn load<S: common_assets::Source + ?Sized>(
|
||||
cache: &common_assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, common_assets::Error> {
|
||||
) -> Result<Self, common_assets::BoxedError> {
|
||||
// List language directories
|
||||
let languages = common_assets::load_dir::<FindManifests>(specifier, false)
|
||||
.unwrap_or_else(|e| panic!("Failed to get manifests from {}: {:?}", specifier, e))
|
||||
|
@ -31,16 +31,11 @@ pub(crate) struct RawLanguage<T> {
|
||||
pub(crate) fragments: HashMap</* relative to i18n_path */ PathBuf, RawFragment<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum RawError {
|
||||
RonError(ron::Error),
|
||||
}
|
||||
|
||||
pub(crate) fn load_manifest(path: &LangPath) -> Result<RawManifest, common_assets::Error> {
|
||||
pub(crate) fn load_manifest(path: &LangPath) -> Result<RawManifest, common_assets::BoxedError> {
|
||||
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<RawManifest, common_asset
|
||||
pub(crate) fn load_raw_language(
|
||||
path: &LangPath,
|
||||
manifest: RawManifest,
|
||||
) -> Result<RawLanguage<String>, common_assets::Error> {
|
||||
) -> Result<RawLanguage<String>, 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<RawLanguage<String>> 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<RawError> 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;
|
||||
|
||||
|
@ -420,10 +420,10 @@ impl assets::Asset for SoundtrackCollection<RawSoundtrackItem> {
|
||||
}
|
||||
|
||||
impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
_: &assets::AssetCache<S>,
|
||||
id: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
let inner = || -> Result<_, assets::Error> {
|
||||
let manifest: AssetHandle<SoundtrackCollection<RawSoundtrackItem>> =
|
||||
AssetExt::load(id)?;
|
||||
|
@ -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<ItemKey, Id>,
|
||||
manifest: AssetHandle<ItemImagesSpec>,
|
||||
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();
|
||||
|
@ -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<u32>,
|
||||
|
||||
shaders: AssetHandle<Shaders>,
|
||||
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
|
||||
|
@ -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<S: assets::source::Source>(
|
||||
fn load<S: assets::source::Source + ?Sized>(
|
||||
_: &assets::AssetCache<S>,
|
||||
_: &str,
|
||||
) -> Result<Shaders, assets::Error> {
|
||||
) -> Result<Shaders, assets::BoxedError> {
|
||||
let shaders = [
|
||||
"include.constants",
|
||||
"include.globals",
|
||||
|
@ -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<FigureKey<Skel::Body>, ((FigureModelEntryFuture<LOD_COUNT>, Skel::Attr), u64)>,
|
||||
manifests: <Skel::Body as BodySpec>::Manifests,
|
||||
watcher: ReloadWatcher,
|
||||
}
|
||||
|
||||
impl<Skel: Skeleton> FigureModelCache<Skel>
|
||||
@ -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 = <Skel::Body as BodySpec>::load_spec().unwrap();
|
||||
let watcher = <Skel::Body as BodySpec>::reload_watcher(&manifests);
|
||||
|
||||
Self {
|
||||
models: HashMap::new(),
|
||||
// NOTE: It might be better to bubble this error up rather than panicking.
|
||||
manifests: <Skel::Body as BodySpec>::load_spec().unwrap(),
|
||||
manifests,
|
||||
watcher,
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,7 +567,7 @@ where
|
||||
{
|
||||
// Check for reloaded manifests
|
||||
// TODO: maybe do this in a different function, maintain?
|
||||
if <Skel::Body as BodySpec>::is_reloaded(&mut self.manifests) {
|
||||
if self.watcher.reloaded() {
|
||||
col_lights.atlas.clear();
|
||||
self.models.clear();
|
||||
}
|
||||
|
@ -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<Self::Manifests, assets::Error>;
|
||||
|
||||
/// 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<S: assets::source::Source>(_: &assets::AssetCache<S>, _: &str) -> Result<Self, assets::Error> {
|
||||
fn load<S: assets::source::Source + ?Sized>(_: &assets::AssetCache<S>, _: &str) -> Result<Self, assets::BoxedError> {
|
||||
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<Self>,
|
||||
@ -4549,7 +4549,7 @@ impl BodySpec for ship::Body {
|
||||
#[allow(unused_variables)]
|
||||
fn load_spec() -> Result<Self::Manifests, assets::Error> { 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<Self>,
|
||||
|
@ -61,7 +61,9 @@ impl BodySpec for VolumeKey {
|
||||
|
||||
fn load_spec() -> Result<Self::Manifests, assets::Error> { Ok(()) }
|
||||
|
||||
fn is_reloaded(_: &mut Self::Manifests) -> bool { false }
|
||||
fn reload_watcher(_: &Self::Manifests) -> assets::ReloadWatcher {
|
||||
assets::ReloadWatcher::default()
|
||||
}
|
||||
|
||||
fn bone_meshes(
|
||||
_: &FigureKey<Self>,
|
||||
|
@ -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<f32>, Aabr<f32>), ()>;
|
||||
// TODO: might not need pub
|
||||
pub type Font = glyph_brush::ab_glyph::FontArc;
|
||||
|
||||
struct FontAsset(Font);
|
||||
struct FontLoader;
|
||||
impl assets::Loader<FontAsset> for FontLoader {
|
||||
fn load(data: Cow<[u8]>, _: &str) -> Result<FontAsset, assets::BoxedError> {
|
||||
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);
|
||||
|
@ -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<Pack> {
|
||||
self.rules
|
||||
|
@ -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::<std::io::Error>() {
|
||||
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;
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user