mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Update assets_manager
to 0.5
This commit is contained in:
parent
f983295318
commit
1cba7db9b6
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -214,9 +214,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "assets_manager"
|
||||
version = "0.4.4"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "792c2eca2af86c76ffd3e72ca564c33b5a5551d5ac3f4f87dce8c0b7c6434061"
|
||||
checksum = "f17769d44fe3eee8cdc255520183fee4e76b30f105de6431cd034e1d7a6f0499"
|
||||
dependencies = [
|
||||
"ahash 0.7.4",
|
||||
"bincode",
|
||||
@ -6143,7 +6143,6 @@ name = "veloren-world"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"arr_macro",
|
||||
"assets_manager",
|
||||
"bincode",
|
||||
"bitvec",
|
||||
"criterion",
|
||||
|
@ -27,9 +27,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
},
|
||||
|
@ -27,7 +27,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
// Texts used in multiple locations with the same formatting
|
||||
"common.username": "jméno",
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
// Texts used in multiple locations with the same formatting
|
||||
|
@ -27,9 +27,6 @@
|
||||
scale_ratio: 0.9,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
string_map: {
|
||||
|
||||
},
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 0.9,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
// Texts used in multiple locations with the same formatting
|
||||
|
@ -41,7 +41,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
// Texts used in multiple locations with the same formatting
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
// Texts used in multiple locations with the same formatting
|
||||
|
@ -29,7 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -41,9 +41,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
|
@ -29,9 +29,6 @@
|
||||
scale_ratio: 1.0,
|
||||
),
|
||||
},
|
||||
sub_directories: [
|
||||
"hud"
|
||||
],
|
||||
|
||||
string_map: {
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
scale_ratio: 0.75,
|
||||
),
|
||||
},
|
||||
sub_directories: [],
|
||||
string_map: {
|
||||
/// Start Common section
|
||||
// Texts used in multiple locations with the same formatting
|
||||
|
@ -7,7 +7,7 @@ version = "0.10.0"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]}
|
||||
assets_manager = {version = "0.5.0", features = ["bincode", "ron", "json", "hot-reloading"]}
|
||||
ron = { version = "0.6", default-features = false }
|
||||
dot_vox = "4.0"
|
||||
image = { version = "0.23.12", default-features = false, features = ["png"] }
|
||||
|
@ -3,19 +3,15 @@
|
||||
use dot_vox::DotVoxData;
|
||||
use image::DynamicImage;
|
||||
use lazy_static::lazy_static;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{borrow::Cow, path::PathBuf, sync::Arc};
|
||||
|
||||
pub use assets_manager::{
|
||||
asset::Ron,
|
||||
asset::{DirLoadable, Ron},
|
||||
loader::{
|
||||
self, BincodeLoader, BytesLoader, JsonLoader, LoadFrom, Loader, RonLoader, StringLoader,
|
||||
},
|
||||
source, Asset, AssetCache, BoxedError, Compound, Error,
|
||||
source::{self, Source},
|
||||
Asset, AssetCache, BoxedError, Compound, Error, SharedString,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
@ -28,7 +24,7 @@ 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 AssetDir<T> = assets_manager::DirReader<'static, T, source::FileSystem>;
|
||||
pub type AssetDirHandle<T> = assets_manager::DirHandle<'static, T, source::FileSystem>;
|
||||
|
||||
/// The Asset trait, which is implemented by all structures that have their data
|
||||
/// stored in the filesystem.
|
||||
@ -51,6 +47,13 @@ pub trait AssetExt: Sized + Send + Sync + 'static {
|
||||
Self::load(specifier).map(AssetHandle::cloned)
|
||||
}
|
||||
|
||||
fn load_or_insert_with(
|
||||
specifier: &str,
|
||||
default: impl FnOnce(Error) -> Self,
|
||||
) -> AssetHandle<Self> {
|
||||
Self::load(specifier).unwrap_or_else(|err| Self::get_or_insert(specifier, default(err)))
|
||||
}
|
||||
|
||||
/// Function used to load essential assets from the filesystem or the cache.
|
||||
/// It will panic if the asset is not found. Example usage:
|
||||
/// ```no_run
|
||||
@ -79,16 +82,31 @@ pub trait AssetExt: Sized + Send + Sync + 'static {
|
||||
}
|
||||
|
||||
fn load_owned(specifier: &str) -> Result<Self, Error>;
|
||||
|
||||
fn get_or_insert(specifier: &str, default: Self) -> AssetHandle<Self>;
|
||||
}
|
||||
|
||||
pub fn load_dir<T: Asset>(specifier: &str) -> Result<AssetDir<T>, Error> {
|
||||
Ok(ASSETS.load_dir(specifier)?)
|
||||
pub fn load_dir<T: DirLoadable>(
|
||||
specifier: &str,
|
||||
recursive: bool,
|
||||
) -> Result<AssetDirHandle<T>, Error> {
|
||||
let specifier = specifier.strip_suffix(".*").unwrap_or(specifier);
|
||||
ASSETS.load_dir(specifier, recursive)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn load_expect_dir<T: DirLoadable>(specifier: &str, recursive: bool) -> AssetDirHandle<T> {
|
||||
load_dir(specifier, recursive).expect("Failed loading directory")
|
||||
}
|
||||
|
||||
impl<T: Compound> AssetExt for T {
|
||||
fn load(specifier: &str) -> Result<AssetHandle<Self>, Error> { ASSETS.load(specifier) }
|
||||
|
||||
fn load_owned(specifier: &str) -> Result<Self, Error> { ASSETS.load_owned(specifier) }
|
||||
|
||||
fn get_or_insert(specifier: &str, default: Self) -> AssetHandle<Self> {
|
||||
ASSETS.get_or_insert(specifier, default)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Image(pub Arc<DynamicImage>);
|
||||
@ -223,52 +241,19 @@ 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) }
|
||||
|
||||
fn get_dir_files(files: &mut Vec<String>, path: &Path, specifier: &str) -> io::Result<()> {
|
||||
for entry in (fs::read_dir(path)?).flatten() {
|
||||
let path = entry.path();
|
||||
let maybe_stem = path.file_stem().and_then(|stem| stem.to_str());
|
||||
|
||||
if let Some(stem) = maybe_stem {
|
||||
let specifier = format!("{}.{}", specifier, stem);
|
||||
|
||||
if path.is_dir() {
|
||||
get_dir_files(files, &path, &specifier)?;
|
||||
} else {
|
||||
files.push(specifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct Directory(Vec<String>);
|
||||
|
||||
impl Directory {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &String> { self.0.iter() }
|
||||
}
|
||||
|
||||
impl Compound for Directory {
|
||||
fn load<S: source::Source>(_: &AssetCache<S>, specifier: &str) -> Result<Self, Error> {
|
||||
let specifier = specifier.strip_suffix(".*").unwrap_or(specifier);
|
||||
let root = ASSETS.source().path_of(specifier, "");
|
||||
let mut files = Vec::new();
|
||||
|
||||
get_dir_files(&mut files, &root, specifier)?;
|
||||
|
||||
Ok(Directory(files))
|
||||
}
|
||||
pub fn path_of(specifier: &str, ext: &str) -> PathBuf {
|
||||
ASSETS
|
||||
.source()
|
||||
.path_of(source::DirEntry::File(specifier, ext))
|
||||
}
|
||||
|
||||
#[warn(clippy::pedantic)]
|
||||
#[cfg(feature = "asset_tweak")]
|
||||
pub mod asset_tweak {
|
||||
// Return path to repository by searching 10 directories back
|
||||
use super::{find_root, fs, Asset, AssetExt, Path, RonLoader};
|
||||
use super::{find_root, Asset, AssetExt, RonLoader};
|
||||
use ron::ser::{to_writer_pretty, PrettyConfig};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
struct AssetTweakWrapper<T>(T);
|
||||
|
@ -514,9 +514,10 @@ impl assets::Compound for ItemDef {
|
||||
) -> Result<Self, Error> {
|
||||
// load from the filesystem first, but if the file doesn't exist, see if it's a
|
||||
// programmaticly-generated asset
|
||||
let raw = cache
|
||||
.load_owned::<RawItemDef>(specifier)
|
||||
.or_else(|e| modular::synthesize_modular_asset(specifier).ok_or(e))?;
|
||||
let raw = match cache.load::<RawItemDef>(specifier) {
|
||||
Ok(handle) => handle.cloned(),
|
||||
Err(e) => modular::synthesize_modular_asset(specifier).ok_or(e)?,
|
||||
};
|
||||
|
||||
let RawItemDef {
|
||||
name,
|
||||
@ -569,24 +570,6 @@ impl assets::Asset for RawItemDef {
|
||||
#[derive(Debug)]
|
||||
pub struct OperationFailure;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ItemList(Vec<Item>);
|
||||
impl assets::Compound for ItemList {
|
||||
fn load<S: assets::source::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
let list = cache
|
||||
.load::<assets::Directory>(specifier)?
|
||||
.read()
|
||||
.iter()
|
||||
.map(|spec| Item::new_from_asset(spec))
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
Ok(ItemList(list))
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
// TODO: consider alternatives such as default abilities that can be added to a
|
||||
// loadout when no weapon is present
|
||||
@ -634,7 +617,9 @@ impl Item {
|
||||
/// Creates a Vec containing one of each item that matches the provided
|
||||
/// asset glob pattern
|
||||
pub fn new_from_asset_glob(asset_glob: &str) -> Result<Vec<Self>, Error> {
|
||||
Ok(ItemList::load_cloned(asset_glob)?.0)
|
||||
let specifier = asset_glob.strip_suffix(".*").unwrap_or(asset_glob);
|
||||
let defs = assets::load_dir::<RawItemDef>(specifier, true)?;
|
||||
defs.ids().map(Item::new_from_asset).collect()
|
||||
}
|
||||
|
||||
/// Creates a new instance of an `Item from the provided asset identifier if
|
||||
|
@ -716,10 +716,7 @@ impl LoadoutBuilder {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
assets::{AssetExt, Error},
|
||||
comp::{self, Body},
|
||||
};
|
||||
use crate::comp::{self, Body};
|
||||
use rand::thread_rng;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
@ -788,31 +785,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_all_loadout_assets() {
|
||||
#[derive(Clone)]
|
||||
struct LoadoutList(Vec<LoadoutSpec>);
|
||||
impl assets::Compound for LoadoutList {
|
||||
fn load<S: assets::source::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
let list = cache
|
||||
.load::<assets::Directory>(specifier)?
|
||||
.read()
|
||||
.iter()
|
||||
.map(|spec| LoadoutSpec::load_cloned(spec))
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
Ok(Self(list))
|
||||
}
|
||||
}
|
||||
|
||||
// It just load everything that could
|
||||
// TODO: add some checks, e.g. that Armor(Head) key correspond
|
||||
// to Item with ItemKind Head(_)
|
||||
let loadouts = LoadoutList::load_expect_cloned("common.loadout.*").0;
|
||||
for loadout in loadouts {
|
||||
let spec = loadout.0;
|
||||
for (key, entry) in spec {
|
||||
let loadouts = assets::load_expect_dir::<LoadoutSpec>("common.loadout", true);
|
||||
for loadout in loadouts.iter() {
|
||||
let spec = loadout.read();
|
||||
for (&key, entry) in &spec.0 {
|
||||
entry.validate(key);
|
||||
}
|
||||
}
|
||||
|
@ -308,31 +308,12 @@ pub fn get_npc_name<
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{comp::inventory::slot::EquipSlot, SkillSetBuilder};
|
||||
use assets::Error;
|
||||
|
||||
#[test]
|
||||
fn test_all_entity_assets() {
|
||||
#[derive(Clone)]
|
||||
struct EntityList(Vec<EntityConfig>);
|
||||
impl assets::Compound for EntityList {
|
||||
fn load<S: assets::source::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
let list = cache
|
||||
.load::<assets::Directory>(specifier)?
|
||||
.read()
|
||||
.iter()
|
||||
.map(|spec| EntityConfig::load_cloned(spec))
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
Ok(Self(list))
|
||||
}
|
||||
}
|
||||
|
||||
// It just load everything that could
|
||||
let entity_configs = EntityList::load_expect_cloned("common.entity.*").0;
|
||||
for config in entity_configs {
|
||||
let entity_configs = assets::load_expect_dir::<EntityConfig>("common.entity", true);
|
||||
for config in entity_configs.iter() {
|
||||
let EntityConfig {
|
||||
main_tool,
|
||||
second_tool,
|
||||
@ -341,7 +322,7 @@ mod tests {
|
||||
name: _name,
|
||||
body,
|
||||
loot,
|
||||
} = config;
|
||||
} = config.cloned();
|
||||
|
||||
if let Some(main_tool) = main_tool {
|
||||
main_tool.validate(EquipSlot::ActiveMainhand);
|
||||
|
@ -111,31 +111,10 @@ impl LootSpec {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
assets::{AssetExt, Error},
|
||||
comp::Item,
|
||||
};
|
||||
use crate::{assets, comp::Item};
|
||||
|
||||
#[test]
|
||||
fn test_loot_tables() {
|
||||
#[derive(Clone)]
|
||||
struct LootTableList(Vec<Lottery<LootSpec>>);
|
||||
impl assets::Compound for LootTableList {
|
||||
fn load<S: assets::source::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
let list = cache
|
||||
.load::<assets::Directory>(specifier)?
|
||||
.read()
|
||||
.iter()
|
||||
.map(|spec| Lottery::<LootSpec>::load_cloned(spec))
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
Ok(LootTableList(list))
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_table_contents(table: Lottery<LootSpec>) {
|
||||
for (_, item) in table.iter() {
|
||||
match item {
|
||||
@ -165,9 +144,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
let loot_tables = LootTableList::load_expect_cloned("common.loot_tables.*").0;
|
||||
for loot_table in loot_tables {
|
||||
validate_table_contents(loot_table);
|
||||
let loot_tables = assets::load_expect_dir::<Lottery<LootSpec>>("common.loot_tables", true);
|
||||
for loot_table in loot_tables.iter() {
|
||||
validate_table_contents(loot_table.cloned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ enum SkillNode {
|
||||
|
||||
#[must_use]
|
||||
fn skills_from_asset_expect(asset_specifier: &str) -> Vec<(Skill, Option<u16>)> {
|
||||
let nodes = SkillSetTree::load_expect(asset_specifier).read().0.clone();
|
||||
let nodes = SkillSetTree::load_expect(asset_specifier).read();
|
||||
|
||||
skills_from_nodes(nodes)
|
||||
skills_from_nodes(&nodes.0)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn skills_from_nodes(nodes: Vec<SkillNode>) -> Vec<(Skill, Option<u16>)> {
|
||||
fn skills_from_nodes(nodes: &[SkillNode]) -> Vec<(Skill, Option<u16>)> {
|
||||
let mut skills = Vec::new();
|
||||
for node in nodes {
|
||||
match node {
|
||||
@ -43,10 +43,10 @@ fn skills_from_nodes(nodes: Vec<SkillNode>) -> Vec<(Skill, Option<u16>)> {
|
||||
skills.append(&mut skills_from_asset_expect(&asset));
|
||||
},
|
||||
SkillNode::Skill(req) => {
|
||||
skills.push(req);
|
||||
skills.push(*req);
|
||||
},
|
||||
SkillNode::Group(group) => {
|
||||
skills.push((Skill::UnlockGroup(group), None));
|
||||
skills.push((Skill::UnlockGroup(*group), None));
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -148,34 +148,14 @@ fn skill_is_applied(skill_set: &SkillSet, skill: Skill, level: Option<u16>) -> b
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use assets::Error;
|
||||
|
||||
#[test]
|
||||
fn test_all_skillset_assets() {
|
||||
#[derive(Clone)]
|
||||
struct SkillSetList(Vec<SkillSetTree>);
|
||||
|
||||
impl assets::Compound for SkillSetList {
|
||||
fn load<S: assets::source::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, Error> {
|
||||
let list = cache
|
||||
.load::<assets::Directory>(specifier)?
|
||||
.read()
|
||||
.iter()
|
||||
.map(|spec| SkillSetTree::load_cloned(spec))
|
||||
.collect::<Result<_, Error>>()?;
|
||||
|
||||
Ok(Self(list))
|
||||
}
|
||||
}
|
||||
|
||||
let skillsets = SkillSetList::load_expect_cloned("common.skillset.*").0;
|
||||
for skillset in skillsets {
|
||||
let skillsets = assets::load_expect_dir::<SkillSetTree>("common.skillset", true);
|
||||
for skillset in skillsets.iter() {
|
||||
std::mem::drop({
|
||||
let mut skillset_builder = SkillSetBuilder::default();
|
||||
let nodes = skillset.0;
|
||||
let nodes = &*skillset.read().0;
|
||||
let tree = skills_from_nodes(nodes);
|
||||
for (skill, level) in tree {
|
||||
skillset_builder = skillset_builder.with_skill(skill, level);
|
||||
|
@ -222,7 +222,7 @@ fn complete_key_versions<'a>(
|
||||
) {
|
||||
//TODO: review unwraps in this file
|
||||
|
||||
// For each file (if it's not a directory) in directory
|
||||
// For each file in directory
|
||||
for i18n_file in root_dir.join(&lang_dir).read_dir().unwrap().flatten() {
|
||||
if let Ok(file_type) = i18n_file.file_type() {
|
||||
if file_type.is_file() {
|
||||
@ -240,6 +240,15 @@ fn complete_key_versions<'a>(
|
||||
)
|
||||
});
|
||||
i18n_key_versions.extend(generate_key_version(&repo, &i18n, &path, &i18n_blob));
|
||||
} else if file_type.is_dir() {
|
||||
// If it's a directory, recursively check it
|
||||
complete_key_versions(
|
||||
repo,
|
||||
head_ref,
|
||||
i18n_key_versions,
|
||||
root_dir,
|
||||
&i18n_file.path(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,12 +274,6 @@ fn gather_state(
|
||||
// Gathering info about keys from language
|
||||
complete_key_versions(repo, head_ref, &mut i18n_map, root_dir, lang_dir);
|
||||
|
||||
// read HEAD for the subfolders
|
||||
for sub_directory in loc.sub_directories.iter() {
|
||||
let subdir_path = &lang_dir.join(sub_directory);
|
||||
complete_key_versions(repo, head_ref, &mut i18n_map, root_dir, subdir_path);
|
||||
}
|
||||
|
||||
i18n_map
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::assets::{self, AssetExt, AssetGuard, AssetHandle};
|
||||
use crate::assets::{self, source::DirEntry, AssetExt, AssetGuard, AssetHandle};
|
||||
use deunicode::deunicode;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs,
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tracing::warn;
|
||||
@ -52,7 +52,6 @@ pub type Fonts = HashMap<String, Font>;
|
||||
/// See `Language` for more info on each attributes
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
pub(crate) struct RawLocalization {
|
||||
pub(crate) sub_directories: Vec<String>,
|
||||
pub(crate) convert_utf8_to_ascii: bool,
|
||||
pub(crate) fonts: Fonts,
|
||||
pub(crate) metadata: LanguageMetadata,
|
||||
@ -63,9 +62,6 @@ pub(crate) struct RawLocalization {
|
||||
/// Store internationalization data
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct Language {
|
||||
/// A list of subdirectories to lookup for localization files
|
||||
pub(crate) sub_directories: Vec<String>,
|
||||
|
||||
/// A map storing the localized texts
|
||||
///
|
||||
/// Localized content can be accessed using a String key.
|
||||
@ -127,7 +123,6 @@ impl Language {
|
||||
impl Default for Language {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sub_directories: Vec::default(),
|
||||
string_map: HashMap::default(),
|
||||
vector_map: HashMap::default(),
|
||||
..Default::default()
|
||||
@ -138,7 +133,6 @@ impl Default for Language {
|
||||
impl From<RawLocalization> for Language {
|
||||
fn from(raw: RawLocalization) -> Self {
|
||||
Self {
|
||||
sub_directories: raw.sub_directories,
|
||||
string_map: raw.string_map,
|
||||
vector_map: raw.vector_map,
|
||||
convert_utf8_to_ascii: raw.convert_utf8_to_ascii,
|
||||
@ -179,7 +173,10 @@ impl assets::Compound for Language {
|
||||
|
||||
// Walk through files in the folder, collecting localization fragment to merge
|
||||
// inside the asked_localization
|
||||
for localization_asset in cache.load_dir::<LocalizationFragment>(asset_key)?.iter() {
|
||||
for localization_asset in cache
|
||||
.load_dir::<LocalizationFragment>(asset_key, true)?
|
||||
.iter()
|
||||
{
|
||||
localization
|
||||
.string_map
|
||||
.extend(localization_asset.read().string_map.clone());
|
||||
@ -188,21 +185,6 @@ impl assets::Compound for Language {
|
||||
.extend(localization_asset.read().vector_map.clone());
|
||||
}
|
||||
|
||||
// Use the localization's subdirectory list to load fragments from there
|
||||
for sub_directory in localization.sub_directories.iter() {
|
||||
for localization_asset in cache
|
||||
.load_dir::<LocalizationFragment>(&[asset_key, ".", sub_directory].concat())?
|
||||
.iter()
|
||||
{
|
||||
localization
|
||||
.string_map
|
||||
.extend(localization_asset.read().string_map.clone());
|
||||
localization
|
||||
.vector_map
|
||||
.extend(localization_asset.read().vector_map.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Update the text if UTF-8 to ASCII conversion is enabled
|
||||
if localization.convert_utf8_to_ascii {
|
||||
for value in localization.string_map.values_mut() {
|
||||
@ -353,28 +335,48 @@ impl LocalizationHandle {
|
||||
pub fn reloaded(&mut self) -> bool { self.active.reloaded() }
|
||||
}
|
||||
|
||||
struct FindManifests;
|
||||
|
||||
impl assets::Compound for FindManifests {
|
||||
fn load<S: assets::Source>(_: &assets::AssetCache<S>, _: &str) -> Result<Self, assets::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl assets::DirLoadable for FindManifests {
|
||||
fn select_ids<S: assets::Source + ?Sized>(
|
||||
source: &S,
|
||||
specifier: &str,
|
||||
) -> io::Result<Vec<assets::SharedString>> {
|
||||
let mut specifiers = Vec::new();
|
||||
|
||||
source.read_dir(specifier, &mut |entry| {
|
||||
if let DirEntry::Directory(spec) = entry {
|
||||
let manifest_spec = [spec, ".", LANG_MANIFEST_FILE].concat();
|
||||
if source.exists(DirEntry::File(&manifest_spec, "ron")) {
|
||||
specifiers.push(manifest_spec.into());
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(specifiers)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct LocalizationList(Vec<LanguageMetadata>);
|
||||
|
||||
impl assets::Compound for LocalizationList {
|
||||
fn load<S: assets::source::Source>(
|
||||
fn load<S: assets::Source>(
|
||||
cache: &assets::AssetCache<S>,
|
||||
specifier: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
// List language directories
|
||||
let mut languages = vec![];
|
||||
|
||||
let i18n_root = assets::path_of(specifier, "");
|
||||
for i18n_entry in (std::fs::read_dir(&i18n_root)?).flatten() {
|
||||
if let Some(i18n_key) = i18n_entry.file_name().to_str() {
|
||||
// load the root file of all the subdirectories
|
||||
if let Ok(localization) = cache.load::<RawLocalization>(
|
||||
&[specifier, ".", i18n_key, ".", LANG_MANIFEST_FILE].concat(),
|
||||
) {
|
||||
languages.push(localization.read().metadata.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
let languages = assets::load_expect_dir::<FindManifests>(specifier, false)
|
||||
.ids()
|
||||
.filter_map(|spec| cache.load::<RawLocalization>(spec).ok())
|
||||
.map(|localization| localization.read().metadata.clone())
|
||||
.collect();
|
||||
|
||||
Ok(LocalizationList(languages))
|
||||
}
|
||||
@ -385,9 +387,6 @@ pub fn list_localizations() -> Vec<LanguageMetadata> {
|
||||
LocalizationList::load_expect_cloned("voxygen.i18n").0
|
||||
}
|
||||
|
||||
/// Start hot reloading of i18n assets
|
||||
pub fn start_hot_reloading() { assets::start_hot_reloading(); }
|
||||
|
||||
/// List localization directories as a `PathBuf` vector
|
||||
pub fn i18n_directories(i18n_dir: &Path) -> Vec<PathBuf> {
|
||||
fs::read_dir(i18n_dir)
|
||||
|
@ -1,9 +1,7 @@
|
||||
use ron::de::from_reader;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use crate::data::{
|
||||
i18n_directories, LocalizationFragment, RawLocalization, LANG_MANIFEST_FILE, REFERENCE_LANG,
|
||||
};
|
||||
use crate::data::{i18n_directories, LocalizationFragment, LANG_MANIFEST_FILE, REFERENCE_LANG};
|
||||
|
||||
fn verify_localization_directory(root_dir: &Path, directory_path: &Path) {
|
||||
// Walk through each file in the directory
|
||||
@ -11,10 +9,7 @@ fn verify_localization_directory(root_dir: &Path, directory_path: &Path) {
|
||||
if let Ok(file_type) = i18n_file.file_type() {
|
||||
// Skip folders and the manifest file (which does not contain the same struct we
|
||||
// want to load)
|
||||
if file_type.is_file()
|
||||
&& i18n_file.file_name().to_string_lossy()
|
||||
!= (LANG_MANIFEST_FILE.to_string() + ".ron")
|
||||
{
|
||||
if file_type.is_file() {
|
||||
let full_path = i18n_file.path();
|
||||
println!("-> {:?}", full_path.strip_prefix(&root_dir).unwrap());
|
||||
let f = fs::File::open(&full_path).expect("Failed opening file");
|
||||
@ -28,6 +23,8 @@ fn verify_localization_directory(root_dir: &Path, directory_path: &Path) {
|
||||
);
|
||||
},
|
||||
};
|
||||
} else if file_type.is_dir() {
|
||||
verify_localization_directory(root_dir, &i18n_file.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,29 +57,11 @@ pub fn verify_all_localizations(root_dir: &Path, asset_path: &Path) {
|
||||
folder is empty?"
|
||||
);
|
||||
for i18n_directory in i18n_directories {
|
||||
// Attempt to load the manifest file
|
||||
let manifest_path = i18n_directory.join(LANG_MANIFEST_FILE.to_string() + ".ron");
|
||||
println!(
|
||||
"verifying {:?}",
|
||||
manifest_path.strip_prefix(&root_dir).unwrap()
|
||||
i18n_directory.strip_prefix(&root_dir).unwrap()
|
||||
);
|
||||
let f = fs::File::open(&manifest_path).expect("Failed opening file");
|
||||
let raw_localization: RawLocalization = match from_reader(f) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"Could not parse {} RON file, error: {}",
|
||||
i18n_directory.to_string_lossy(),
|
||||
e
|
||||
);
|
||||
},
|
||||
};
|
||||
// Walk through each files and try to load them
|
||||
verify_localization_directory(root_dir, &i18n_directory);
|
||||
// Walk through each subdirectories and try to load files in them
|
||||
for sub_directory in raw_localization.sub_directories.iter() {
|
||||
let subdir_path = &i18n_directory.join(sub_directory);
|
||||
verify_localization_directory(root_dir, &subdir_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +127,13 @@ impl AmbientMgr {
|
||||
}
|
||||
|
||||
fn load_soundtrack_items() -> AssetHandle<AmbientCollection> {
|
||||
// Cannot fail: A default value is always provided
|
||||
AmbientCollection::load_expect("voxygen.audio.ambient")
|
||||
AmbientCollection::load_or_insert_with("voxygen.audio.ambient", |error| {
|
||||
warn!(
|
||||
"Error reading ambience config file, ambience will not be available: {:#?}",
|
||||
error
|
||||
);
|
||||
AmbientCollection::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,13 +141,4 @@ impl assets::Asset for AmbientCollection {
|
||||
type Loader = assets::RonLoader;
|
||||
|
||||
const EXTENSION: &'static str = "ron";
|
||||
|
||||
fn default_value(_: &str, error: assets::Error) -> Result<Self, assets::Error> {
|
||||
warn!(
|
||||
"Error reading ambience config file, ambience will not be available: {:#?}",
|
||||
error
|
||||
);
|
||||
|
||||
Ok(AmbientCollection::default())
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag,
|
||||
use fader::Fader;
|
||||
use music::MusicTransitionManifest;
|
||||
use sfx::{SfxEvent, SfxTriggerItem};
|
||||
use soundcache::OggSound;
|
||||
use soundcache::load_ogg;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
@ -101,6 +101,15 @@ impl AudioFrontend {
|
||||
|
||||
/// Construct in `no-audio` mode for debugging
|
||||
pub fn no_audio() -> Self {
|
||||
let audio_manifest = "voxygen.audio.music_transition_manifest";
|
||||
let mtm = MusicTransitionManifest::load_or_insert_with(audio_manifest, |err| {
|
||||
warn!(
|
||||
"Error loading MusicTransitionManifest {:?}: {:?}",
|
||||
audio_manifest, err
|
||||
);
|
||||
MusicTransitionManifest::default()
|
||||
});
|
||||
|
||||
Self {
|
||||
// The following is for the disabled device switcher
|
||||
//device: "".to_string(),
|
||||
@ -115,9 +124,7 @@ impl AudioFrontend {
|
||||
music_volume: 1.0,
|
||||
master_volume: 1.0,
|
||||
listener: Listener::default(),
|
||||
// This expect should be fine, since `<MusicTransitionManifest as Asset>::default_value`
|
||||
// is specified
|
||||
mtm: AssetExt::load_expect("voxygen.audio.music_transition_manifest"),
|
||||
mtm,
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,10 +271,7 @@ impl AudioFrontend {
|
||||
underwater: bool,
|
||||
) -> Result<(), rodio::decoder::DecoderError> {
|
||||
if self.audio_stream.is_some() {
|
||||
let sound = OggSound::load_expect(sound)
|
||||
.read()
|
||||
.to_source()
|
||||
.amplify(vol.unwrap_or(1.0));
|
||||
let sound = load_ogg(sound).amplify(vol.unwrap_or(1.0));
|
||||
|
||||
let listener = self.listener.clone();
|
||||
if let Some(channel) = self.get_sfx_channel() {
|
||||
@ -291,7 +295,7 @@ impl AudioFrontend {
|
||||
) {
|
||||
if self.audio_stream.is_some() {
|
||||
if let Some(channel) = self.get_ambient_channel(channel_tag, volume_multiplier) {
|
||||
channel.play(OggSound::load_expect(sound).read().to_source());
|
||||
channel.play(load_ogg(sound));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,7 +351,7 @@ impl AudioFrontend {
|
||||
fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) {
|
||||
if self.music_enabled() {
|
||||
if let Some(channel) = self.get_music_channel(channel_tag) {
|
||||
channel.play(OggSound::load_expect(sound).read().to_source(), channel_tag);
|
||||
channel.play(load_ogg(sound), channel_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,11 +191,6 @@ impl assets::Asset for MusicTransitionManifest {
|
||||
type Loader = assets::RonLoader;
|
||||
|
||||
const EXTENSION: &'static str = "ron";
|
||||
|
||||
fn default_value(id: &str, e: assets::Error) -> Result<MusicTransitionManifest, assets::Error> {
|
||||
warn!("Error loading MusicTransitionManifest {:?}: {:?}", id, e);
|
||||
Ok(MusicTransitionManifest::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MusicMgr {
|
||||
@ -429,10 +424,10 @@ impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
||||
id: &str,
|
||||
) -> Result<Self, assets::Error> {
|
||||
let inner = || -> Result<_, assets::Error> {
|
||||
let manifest: AssetHandle<assets::Ron<SoundtrackCollection<RawSoundtrackItem>>> =
|
||||
let manifest: AssetHandle<SoundtrackCollection<RawSoundtrackItem>> =
|
||||
AssetExt::load(id)?;
|
||||
let mut soundtracks = SoundtrackCollection::default();
|
||||
for item in manifest.read().0.tracks.iter().cloned() {
|
||||
for item in manifest.read().tracks.iter().cloned() {
|
||||
match item {
|
||||
RawSoundtrackItem::Individual(track) => soundtracks.tracks.push(track),
|
||||
RawSoundtrackItem::Segmented {
|
||||
|
@ -558,8 +558,14 @@ impl SfxMgr {
|
||||
}
|
||||
|
||||
fn load_sfx_items() -> AssetHandle<SfxTriggers> {
|
||||
// Cannot fail: A default value is always provided
|
||||
SfxTriggers::load_expect("voxygen.audio.sfx")
|
||||
SfxTriggers::load_or_insert_with("voxygen.audio.sfx", |error| {
|
||||
warn!(
|
||||
"Error reading sfx config file, sfx will not be available: {:#?}",
|
||||
error
|
||||
);
|
||||
|
||||
SfxTriggers::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -567,13 +573,4 @@ impl assets::Asset for SfxTriggers {
|
||||
type Loader = assets::RonLoader;
|
||||
|
||||
const EXTENSION: &'static str = "ron";
|
||||
|
||||
fn default_value(_: &str, error: assets::Error) -> Result<Self, assets::Error> {
|
||||
warn!(
|
||||
"Error reading sfx config file, sfx will not be available: {:#?}",
|
||||
error
|
||||
);
|
||||
|
||||
Ok(SfxTriggers::default())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Handles caching and retrieval of decoded `.ogg` sfx sound data, eliminating
|
||||
//! the need to decode files on each playback
|
||||
use common::assets::{self, Loader};
|
||||
use common::assets::{self, AssetExt, Loader};
|
||||
use rodio::{source::Buffered, Decoder, Source};
|
||||
use std::{borrow::Cow, io};
|
||||
use tracing::warn;
|
||||
@ -8,14 +8,13 @@ use tracing::warn;
|
||||
// Implementation of sound taken from this github issue:
|
||||
// https://github.com/RustAudio/rodio/issues/141
|
||||
|
||||
pub struct SoundLoader;
|
||||
|
||||
struct SoundLoader;
|
||||
#[derive(Clone)]
|
||||
pub struct OggSound(Buffered<Decoder<io::Cursor<Vec<u8>>>>);
|
||||
struct OggSound(Buffered<Decoder<io::Cursor<Vec<u8>>>>);
|
||||
|
||||
impl Loader<OggSound> for SoundLoader {
|
||||
fn load(content: Cow<[u8]>, _: &str) -> Result<OggSound, assets::BoxedError> {
|
||||
let source = Decoder::new(io::Cursor::new(content.into_owned()))?.buffered();
|
||||
let source = Decoder::new_vorbis(io::Cursor::new(content.into_owned()))?.buffered();
|
||||
Ok(OggSound(source))
|
||||
}
|
||||
}
|
||||
@ -34,13 +33,20 @@ impl assets::Asset for OggSound {
|
||||
|
||||
/// Wrapper for decoded audio data
|
||||
impl OggSound {
|
||||
pub fn to_source(&self) -> impl Source + Iterator<Item = i16> { self.0.clone() }
|
||||
|
||||
pub fn empty() -> OggSound {
|
||||
SoundLoader::load(
|
||||
Cow::Borrowed(include_bytes!("../../../assets/voxygen/audio/null.ogg")),
|
||||
"empty",
|
||||
"ogg",
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_ogg(specifier: &str) -> impl Source + Iterator<Item = i16> {
|
||||
OggSound::load_or_insert_with(specifier, |error| {
|
||||
warn!(?specifier, ?error, "Failed to load sound");
|
||||
OggSound::empty()
|
||||
})
|
||||
.cloned()
|
||||
.0
|
||||
}
|
||||
|
@ -144,7 +144,6 @@ fn main() {
|
||||
}));
|
||||
|
||||
assets::start_hot_reloading();
|
||||
i18n::start_hot_reloading();
|
||||
|
||||
// Initialise watcher for animation hotreloading
|
||||
#[cfg(feature = "hot-anim")]
|
||||
|
@ -34,7 +34,6 @@ packed_simd = { package = "packed_simd_2", version = "0.3.5" }
|
||||
rayon = "1.5"
|
||||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
ron = { version = "0.6", default-features = false }
|
||||
assets_manager = {version = "0.4.3", features = ["ron"]}
|
||||
# inline_tweak = "1.0.2"
|
||||
|
||||
# compression benchmarks
|
||||
|
Loading…
Reference in New Issue
Block a user