Update assets_manager to 0.5

This commit is contained in:
Benoît du Garreau 2021-06-25 18:47:03 +02:00
parent f983295318
commit 1cba7db9b6
38 changed files with 165 additions and 344 deletions

5
Cargo.lock generated
View File

@ -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",

View File

@ -27,9 +27,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {
},

View File

@ -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",

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -41,7 +41,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {
/// Start Common section
// Texts used in multiple locations with the same formatting

View File

@ -27,9 +27,6 @@
scale_ratio: 0.9,
),
},
sub_directories: [
"hud"
],
string_map: {
},

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -29,9 +29,6 @@
scale_ratio: 0.9,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -41,7 +41,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {
/// Start Common section
// Texts used in multiple locations with the same formatting

View File

@ -41,7 +41,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {
/// Start Common section
// Texts used in multiple locations with the same formatting

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -27,7 +27,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {
/// Start Common section
// Texts used in multiple locations with the same formatting

View File

@ -29,7 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -41,9 +41,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -29,7 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [],
string_map: {
/// Start Common section

View File

@ -29,9 +29,6 @@
scale_ratio: 1.0,
),
},
sub_directories: [
"hud"
],
string_map: {

View File

@ -27,7 +27,6 @@
scale_ratio: 0.75,
),
},
sub_directories: [],
string_map: {
/// Start Common section
// Texts used in multiple locations with the same formatting

View File

@ -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"] }

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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
}

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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())
}
}

View File

@ -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);
}
}
}

View File

@ -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 {

View File

@ -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())
}
}

View File

@ -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
}

View File

@ -144,7 +144,6 @@ fn main() {
}));
assets::start_hot_reloading();
i18n::start_hot_reloading();
// Initialise watcher for animation hotreloading
#[cfg(feature = "hot-anim")]

View File

@ -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