diff --git a/CHANGELOG.md b/CHANGELOG.md index 013f41e89d..1113738e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Overhauled world colours - Improved projectile physics - Improved overhead aiming +- Figure meshing no longer blocks the main thread. ### Removed diff --git a/assets/world/manifests/acacias.ron b/assets/world/manifests/acacias.ron index 7a7484c2d0..6f65a0ce0f 100644 --- a/assets/world/manifests/acacias.ron +++ b/assets/world/manifests/acacias.ron @@ -1,24 +1,24 @@ -( - [ - ( - specifier: "world.tree.acacia.1", - center: (17, 18, 4) - ), - ( - specifier: "world.tree.acacia.2", - center: (5, 5, 4) - ), - ( - specifier: "world.tree.acacia.3", - center: (6, 6, 3) - ), - ( - specifier: "world.tree.acacia.4", - center: (12, 14, 4) - ), - ( - specifier: "world.tree.acacia.5", - center: (19, 19, 4) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.acacia.1", + center: (17, 18, 4) + ), + ( + specifier: "world.tree.acacia.2", + center: (5, 5, 4) + ), + ( + specifier: "world.tree.acacia.3", + center: (6, 6, 3) + ), + ( + specifier: "world.tree.acacia.4", + center: (12, 14, 4) + ), + ( + specifier: "world.tree.acacia.5", + center: (19, 19, 4) + ), +] diff --git a/assets/world/manifests/birch.ron b/assets/world/manifests/birch.ron index d5cb452b30..0eaa218e1a 100644 --- a/assets/world/manifests/birch.ron +++ b/assets/world/manifests/birch.ron @@ -1,52 +1,52 @@ -( - [ - ( - specifier: "world.tree.birch.1", - center: (12, 9, 10) - ), - ( - specifier: "world.tree.birch.2", - center: (12, 10, 10) - ), - ( - specifier: "world.tree.birch.3", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.4", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.5", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.6", - center: (9, 9, 10) - ), - ( - specifier: "world.tree.birch.7", - center: (10, 10, 10) - ), - ( - specifier: "world.tree.birch.8", - center: (9, 9, 10) - ), - ( - specifier: "world.tree.birch.9", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.10", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.11", - center: (9, 10, 10) - ), - ( - specifier: "world.tree.birch.12", - center: (9, 10, 10) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.birch.1", + center: (12, 9, 10) + ), + ( + specifier: "world.tree.birch.2", + center: (12, 10, 10) + ), + ( + specifier: "world.tree.birch.3", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.4", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.5", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.6", + center: (9, 9, 10) + ), + ( + specifier: "world.tree.birch.7", + center: (10, 10, 10) + ), + ( + specifier: "world.tree.birch.8", + center: (9, 9, 10) + ), + ( + specifier: "world.tree.birch.9", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.10", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.11", + center: (9, 10, 10) + ), + ( + specifier: "world.tree.birch.12", + center: (9, 10, 10) + ), +] diff --git a/assets/world/manifests/dungeon_entrances.ron b/assets/world/manifests/dungeon_entrances.ron index a90c39e368..bf24627572 100644 --- a/assets/world/manifests/dungeon_entrances.ron +++ b/assets/world/manifests/dungeon_entrances.ron @@ -1,48 +1,48 @@ -( - [ ( - specifier: "world.structure.dungeon.jungle_temple.entrance.1", - center: (50, 40, 10) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.round.1", - center: (21, 17, 28) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.round.2", - center: (20, 28, 15) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.1", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.2", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.3", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.4", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.5", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.pillar_entrance.6", - center: (18, 16, 17) - ), - ( - specifier: "world.structure.dungeon.temperate_entrance.ruins_4", - center: (13, 11, 14) - ), - ( - specifier: "world.structure.dungeon.misc_entrance.tower-ruin", - center: (13, 16, 9) - ), +#![enable(unwrap_newtypes)] - ] -) +[ + ( + specifier: "world.structure.dungeon.jungle_temple.entrance.1", + center: (50, 40, 10) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.round.1", + center: (21, 17, 28) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.round.2", + center: (20, 28, 15) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.1", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.2", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.3", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.4", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.5", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.pillar_entrance.6", + center: (18, 16, 17) + ), + ( + specifier: "world.structure.dungeon.temperate_entrance.ruins_4", + center: (13, 11, 14) + ), + ( + specifier: "world.structure.dungeon.misc_entrance.tower-ruin", + center: (13, 16, 9) + ), +] diff --git a/assets/world/manifests/fruit_trees.ron b/assets/world/manifests/fruit_trees.ron index 85beb0896f..5f629cd53e 100644 --- a/assets/world/manifests/fruit_trees.ron +++ b/assets/world/manifests/fruit_trees.ron @@ -1,28 +1,28 @@ -( - [ - ( - specifier: "world.tree.fruit.1", - center: (6, 6, 7) - ), - ( - specifier: "world.tree.fruit.2", - center: (6, 6, 7) - ), - ( - specifier: "world.tree.fruit.3", - center: (6, 7, 7) - ), - ( - specifier: "world.tree.fruit.4", - center: (3, 3, 7) - ), - ( - specifier: "world.tree.fruit.5", - center: (6, 8, 7) - ), - ( - specifier: "world.tree.fruit.6", - center: (7, 7, 7) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.fruit.1", + center: (6, 6, 7) + ), + ( + specifier: "world.tree.fruit.2", + center: (6, 6, 7) + ), + ( + specifier: "world.tree.fruit.3", + center: (6, 7, 7) + ), + ( + specifier: "world.tree.fruit.4", + center: (3, 3, 7) + ), + ( + specifier: "world.tree.fruit.5", + center: (6, 8, 7) + ), + ( + specifier: "world.tree.fruit.6", + center: (7, 7, 7) + ), +] diff --git a/assets/world/manifests/mangrove_trees.ron b/assets/world/manifests/mangrove_trees.ron index 0dc5983246..88b6c191d5 100644 --- a/assets/world/manifests/mangrove_trees.ron +++ b/assets/world/manifests/mangrove_trees.ron @@ -1,36 +1,36 @@ -( - [ - ( - specifier: "world.tree.mangroves.1", - center: (19, 18, 8) - ), - ( - specifier: "world.tree.mangroves.2", - center: (16, 17, 7) - ), - ( - specifier: "world.tree.mangroves.3", - center: (18, 19, 8) - ), - ( - specifier: "world.tree.mangroves.4", - center: (19, 18, 8) - ), - ( - specifier: "world.tree.mangroves.5", - center: (19, 20, 9) - ), - ( - specifier: "world.tree.mangroves.6", - center: (18, 21, 9) - ), - ( - specifier: "world.tree.mangroves.7", - center: (20, 17, 9) - ), - ( - specifier: "world.tree.mangroves.8", - center: (18, 19, 9) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.mangroves.1", + center: (19, 18, 8) + ), + ( + specifier: "world.tree.mangroves.2", + center: (16, 17, 7) + ), + ( + specifier: "world.tree.mangroves.3", + center: (18, 19, 8) + ), + ( + specifier: "world.tree.mangroves.4", + center: (19, 18, 8) + ), + ( + specifier: "world.tree.mangroves.5", + center: (19, 20, 9) + ), + ( + specifier: "world.tree.mangroves.6", + center: (18, 21, 9) + ), + ( + specifier: "world.tree.mangroves.7", + center: (20, 17, 9) + ), + ( + specifier: "world.tree.mangroves.8", + center: (18, 19, 9) + ), +] diff --git a/assets/world/manifests/oak_stumps.ron b/assets/world/manifests/oak_stumps.ron index 888cb76d74..9d83ad6fb9 100644 --- a/assets/world/manifests/oak_stumps.ron +++ b/assets/world/manifests/oak_stumps.ron @@ -1,40 +1,40 @@ -( - [ - ( - specifier: "world.tree.oak_stump.1", - center: (15, 18, 10) - ), - ( - specifier: "world.tree.oak_stump.2", - center: (15, 18, 10) - ), - ( - specifier: "world.tree.oak_stump.3", - center: (16, 20, 10) - ), - ( - specifier: "world.tree.oak_stump.4", - center: (18, 21, 10) - ), - ( - specifier: "world.tree.oak_stump.5", - center: (18, 18, 10) - ), - ( - specifier: "world.tree.oak_stump.6", - center: (16, 21, 10) - ), - ( - specifier: "world.tree.oak_stump.7", - center: (20, 19, 10) - ), - ( - specifier: "world.tree.oak_stump.8", - center: (22, 20, 10) - ), - ( - specifier: "world.tree.oak_stump.9", - center:(26, 26, 10) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.oak_stump.1", + center: (15, 18, 10) + ), + ( + specifier: "world.tree.oak_stump.2", + center: (15, 18, 10) + ), + ( + specifier: "world.tree.oak_stump.3", + center: (16, 20, 10) + ), + ( + specifier: "world.tree.oak_stump.4", + center: (18, 21, 10) + ), + ( + specifier: "world.tree.oak_stump.5", + center: (18, 18, 10) + ), + ( + specifier: "world.tree.oak_stump.6", + center: (16, 21, 10) + ), + ( + specifier: "world.tree.oak_stump.7", + center: (20, 19, 10) + ), + ( + specifier: "world.tree.oak_stump.8", + center: (22, 20, 10) + ), + ( + specifier: "world.tree.oak_stump.9", + center:(26, 26, 10) + ), +] diff --git a/assets/world/manifests/oaks.ron b/assets/world/manifests/oaks.ron index 53b5faef50..51fd606414 100644 --- a/assets/world/manifests/oaks.ron +++ b/assets/world/manifests/oaks.ron @@ -1,40 +1,40 @@ -( - [ - ( - specifier: "world.tree.oak_green.1", - center: (15, 17, 14) - ), - ( - specifier: "world.tree.oak_green.2", - center: (18, 17, 14) - ), - ( - specifier: "world.tree.oak_green.3", - center: (19, 20, 14) - ), - ( - specifier: "world.tree.oak_green.4", - center: (19, 20, 14) - ), - ( - specifier: "world.tree.oak_green.5", - center: (18, 18, 14) - ), - ( - specifier: "world.tree.oak_green.6", - center: (18, 21, 14) - ), - ( - specifier: "world.tree.oak_green.7", - center: (20, 21, 14) - ), - ( - specifier: "world.tree.oak_green.8", - center: (22, 21, 14) - ), - ( - specifier: "world.tree.oak_green.9", - center:(21, 21, 14) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.oak_green.1", + center: (15, 17, 14) + ), + ( + specifier: "world.tree.oak_green.2", + center: (18, 17, 14) + ), + ( + specifier: "world.tree.oak_green.3", + center: (19, 20, 14) + ), + ( + specifier: "world.tree.oak_green.4", + center: (19, 20, 14) + ), + ( + specifier: "world.tree.oak_green.5", + center: (18, 18, 14) + ), + ( + specifier: "world.tree.oak_green.6", + center: (18, 21, 14) + ), + ( + specifier: "world.tree.oak_green.7", + center: (20, 21, 14) + ), + ( + specifier: "world.tree.oak_green.8", + center: (22, 21, 14) + ), + ( + specifier: "world.tree.oak_green.9", + center:(21, 21, 14) + ), +] diff --git a/assets/world/manifests/palms.ron b/assets/world/manifests/palms.ron index d826c1c7f9..4cd7d8572d 100644 --- a/assets/world/manifests/palms.ron +++ b/assets/world/manifests/palms.ron @@ -1,44 +1,44 @@ -( - [ - ( - specifier: "world.tree.desert_palm.1", - center: (7, 8, 2) - ), - ( - specifier: "world.tree.desert_palm.2", - center: (8, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.3", - center: (7, 8, 2) - ), - ( - specifier: "world.tree.desert_palm.4", - center: (6, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.5", - center: (6, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.6", - center: (7, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.7", - center: (7, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.8", - center: (5, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.9", - center: (7, 7, 2) - ), - ( - specifier: "world.tree.desert_palm.10", - center: (6, 7, 2) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.desert_palm.1", + center: (7, 8, 2) + ), + ( + specifier: "world.tree.desert_palm.2", + center: (8, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.3", + center: (7, 8, 2) + ), + ( + specifier: "world.tree.desert_palm.4", + center: (6, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.5", + center: (6, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.6", + center: (7, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.7", + center: (7, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.8", + center: (5, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.9", + center: (7, 7, 2) + ), + ( + specifier: "world.tree.desert_palm.10", + center: (6, 7, 2) + ), +] diff --git a/assets/world/manifests/pines.ron b/assets/world/manifests/pines.ron index 17d3de6ba1..7710fe37ab 100644 --- a/assets/world/manifests/pines.ron +++ b/assets/world/manifests/pines.ron @@ -1,36 +1,36 @@ -( - [ - ( - specifier: "world.tree.pine_green.1", - center: (15, 15, 14) - ), - ( - specifier: "world.tree.pine_green.2", - center: (15, 15, 14) - ), - ( - specifier: "world.tree.pine_green.3", - center: (17, 15, 12) - ), - ( - specifier: "world.tree.pine_green.4", - center: (10, 8, 12) - ), - ( - specifier: "world.tree.pine_green.5", - center: (12, 12, 12) - ), - ( - specifier: "world.tree.pine_green.6", - center: (11, 10, 12) - ), - ( - specifier: "world.tree.pine_green.7", - center: (16, 15, 12) - ), - ( - specifier: "world.tree.pine_green.8", - center: (12, 10, 12) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.pine_green.1", + center: (15, 15, 14) + ), + ( + specifier: "world.tree.pine_green.2", + center: (15, 15, 14) + ), + ( + specifier: "world.tree.pine_green.3", + center: (17, 15, 12) + ), + ( + specifier: "world.tree.pine_green.4", + center: (10, 8, 12) + ), + ( + specifier: "world.tree.pine_green.5", + center: (12, 12, 12) + ), + ( + specifier: "world.tree.pine_green.6", + center: (11, 10, 12) + ), + ( + specifier: "world.tree.pine_green.7", + center: (16, 15, 12) + ), + ( + specifier: "world.tree.pine_green.8", + center: (12, 10, 12) + ), +] diff --git a/assets/world/manifests/quirky.ron b/assets/world/manifests/quirky.ron index 89bfda777e..c4f9a915f0 100644 --- a/assets/world/manifests/quirky.ron +++ b/assets/world/manifests/quirky.ron @@ -1,12 +1,12 @@ -( - [ - ( - specifier: "world.structure.natural.witch-hut", - center: (10, 13, 9) - ), - ( - specifier: "world.structure.natural.tree-house", - center: (20, 15, 10) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.structure.natural.witch-hut", + center: (10, 13, 9) + ), + ( + specifier: "world.structure.natural.tree-house", + center: (20, 15, 10) + ), +] diff --git a/assets/world/manifests/quirky_dry.ron b/assets/world/manifests/quirky_dry.ron index cad8c89187..3b4814b5f0 100644 --- a/assets/world/manifests/quirky_dry.ron +++ b/assets/world/manifests/quirky_dry.ron @@ -1,16 +1,16 @@ -( - [ - ( - specifier: "world.structure.natural.ribcage-small", - center: (7, 13, 4) - ), - ( - specifier: "world.structure.natural.ribcage-large", - center: (13, 19, 8) - ), - ( - specifier: "world.structure.natural.skull-large", - center: (15, 20, 4) - ), - ] -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.structure.natural.ribcage-small", + center: (7, 13, 4) + ), + ( + specifier: "world.structure.natural.ribcage-large", + center: (13, 19, 8) + ), + ( + specifier: "world.structure.natural.skull-large", + center: (15, 20, 4) + ), +] diff --git a/assets/world/manifests/snow_pines.ron b/assets/world/manifests/snow_pines.ron index 88561a9c20..a70cdad690 100644 --- a/assets/world/manifests/snow_pines.ron +++ b/assets/world/manifests/snow_pines.ron @@ -1,36 +1,36 @@ -( - [ - ( - specifier: "world.tree.snow_pine.1", - center: (15, 15, 14) - ), - ( - specifier: "world.tree.snow_pine.2", - center: (15, 15, 14) - ), - ( - specifier: "world.tree.snow_pine.3", - center: (17, 15, 12) - ), - ( - specifier: "world.tree.snow_pine.4", - center: (10, 8, 12) - ), - ( - specifier: "world.tree.snow_pine.5", - center: (12, 12, 12) - ), - ( - specifier: "world.tree.snow_pine.6", - center: (11, 10, 12) - ), - ( - specifier: "world.tree.snow_pine.7", - center: (16, 15, 12) - ), - ( - specifier: "world.tree.snow_pine.8", - center: (12, 10, 12) - ) - ], -) +#![enable(unwrap_newtypes)] + +[ + ( + specifier: "world.tree.snow_pine.1", + center: (15, 15, 14) + ), + ( + specifier: "world.tree.snow_pine.2", + center: (15, 15, 14) + ), + ( + specifier: "world.tree.snow_pine.3", + center: (17, 15, 12) + ), + ( + specifier: "world.tree.snow_pine.4", + center: (10, 8, 12) + ), + ( + specifier: "world.tree.snow_pine.5", + center: (12, 12, 12) + ), + ( + specifier: "world.tree.snow_pine.6", + center: (11, 10, 12) + ), + ( + specifier: "world.tree.snow_pine.7", + center: (16, 15, 12) + ), + ( + specifier: "world.tree.snow_pine.8", + center: (12, 10, 12) + ), +] diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index e0bbaa349a..12471feb2e 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -1,14 +1,14 @@ //! Load assets (images or voxel data) from files pub mod watch; +use core::{any::Any, fmt, marker::PhantomData}; use dot_vox::DotVoxData; use hashbrown::HashMap; use image::DynamicImage; use lazy_static::lazy_static; +use serde::Deserialize; use serde_json::Value; use std::{ - any::Any, - fmt, fs::{self, File, ReadDir}, io::{BufReader, Read}, path::PathBuf, @@ -61,167 +61,16 @@ lazy_static! { RwLock::new(HashMap::new()); } -// TODO: Remove this function. It's only used in world/ in a really ugly way.To -// do this properly assets should have all their necessary data in one file. A -// ron file could be used to combine voxel data with positioning data for -// example. -/// Function used to load assets from the filesystem or the cache. Permits -/// manipulating the loaded asset with a mapping function. Example usage: -/// ```no_run -/// use vek::*; -/// use veloren_common::{assets, terrain::Structure}; -/// -/// let my_tree_structure = assets::load_map("world.tree.oak_green.1", |s: Structure| { -/// s.with_center(Vec3::new(15, 18, 14)) -/// }) -/// .unwrap(); -/// ``` -pub fn load_map A>( - specifier: &str, - f: F, -) -> Result, Error> { - let assets_write = ASSETS.read().unwrap(); - match assets_write.get(specifier) { - Some(asset) => Ok(Arc::clone(asset).downcast()?), - None => { - drop(assets_write); // Drop the asset hashmap to permit recursive loading - let asset = Arc::new(f(A::parse(load_file(specifier, A::ENDINGS)?)?)); - let clone = Arc::clone(&asset); - ASSETS.write().unwrap().insert(specifier.to_owned(), clone); - Ok(asset) - }, - } -} - -pub fn load_glob(specifier: &str) -> Result>>, Error> { - if let Some(assets) = ASSETS.read().unwrap().get(specifier) { - return Ok(Arc::clone(assets).downcast()?); - } - - // Get glob matches - let glob_matches = read_dir(specifier.trim_end_matches(".*")).map(|dir| { - dir.filter_map(|direntry| { - direntry.ok().and_then(|file| { - file.file_name() - .to_string_lossy() - .rsplitn(2, '.') - .last() - .map(|s| s.to_owned()) - }) - }) - .collect::>() - }); - - match glob_matches { - Ok(glob_matches) => { - let assets = Arc::new( - glob_matches - .into_iter() - .filter_map(|name| { - load(&specifier.replace("*", &name)) - .map_err(|e| { - error!( - ?e, - "Failed to load \"{}\" as part of glob \"{}\"", name, specifier - ) - }) - .ok() - }) - .collect::>(), - ); - let clone = Arc::clone(&assets); - - let mut assets_write = ASSETS.write().unwrap(); - assets_write.insert(specifier.to_owned(), clone); - Ok(assets) - }, - Err(error) => Err(error), - } -} - -/// Function used to load assets from the filesystem or the cache. -/// Example usage: -/// ```no_run -/// use image::DynamicImage; -/// use veloren_common::assets; -/// -/// let my_image = assets::load::("core.ui.backgrounds.city").unwrap(); -/// ``` -pub fn load(specifier: &str) -> Result, Error> { - load_map(specifier, |x| x) -} - -/// Function used to load assets from the filesystem or the cache and return a -/// clone. -pub fn load_cloned(specifier: &str) -> Result { - load::(specifier).map(|asset| (*asset).clone()) -} - -/// 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 -/// use image::DynamicImage; -/// use veloren_common::assets; -/// -/// let my_image = assets::load_expect::("core.ui.backgrounds.city"); -/// ``` -pub fn load_expect(specifier: &str) -> Arc { - load(specifier).unwrap_or_else(|err| { - panic!( - "Failed loading essential asset: {} (error={:?})", - specifier, err - ) - }) -} - -/// Function used to load essential assets from the filesystem or the cache and -/// return a clone. It will panic if the asset is not found. -pub fn load_expect_cloned(specifier: &str) -> A { - load_expect::(specifier).as_ref().clone() -} - -/// Load an asset while registering it to be watched and reloaded when it -/// changes -pub fn load_watched( - specifier: &str, - indicator: &mut watch::ReloadIndicator, -) -> Result, Error> { - let asset = load(specifier)?; - - // Determine path to watch - let path = unpack_specifier(specifier); - let mut path_with_extension = None; - for ending in A::ENDINGS { - let mut path = path.clone(); - path.set_extension(ending); - - if path.exists() { - path_with_extension = Some(path); - break; - } - } - - let owned_specifier = specifier.to_string(); - indicator.add( - path_with_extension.ok_or_else(|| Error::NotFound(path.to_string_lossy().into_owned()))?, - move || { - if let Err(e) = reload::(&owned_specifier) { - error!(?e, ?owned_specifier, "Error reloading owned_specifier"); - } - }, - ); - - Ok(asset) -} - -fn reload(specifier: &str) -> Result<(), Error> { +fn reload(specifier: &str) -> Result<(), Error> +where + A::Output: Send + Sync + 'static, +{ let asset = Arc::new(A::parse(load_file(specifier, A::ENDINGS)?)?); - let clone = Arc::clone(&asset); let mut assets_write = ASSETS.write().unwrap(); match assets_write.get_mut(specifier) { - Some(a) => *a = clone, + Some(a) => *a = asset, None => { - assets_write.insert(specifier.to_owned(), clone); + assets_write.insert(specifier.to_owned(), asset); }, } @@ -230,10 +79,189 @@ fn reload(specifier: &str) -> Result<(), Error> { /// The Asset trait, which is implemented by all structures that have their data /// stored in the filesystem. -pub trait Asset: Send + Sync + Sized { +pub trait Asset: Sized { + type Output = Self; + const ENDINGS: &'static [&'static str]; /// Parse the input file and return the correct Asset. - fn parse(buf_reader: BufReader) -> Result; + fn parse(buf_reader: BufReader) -> Result; + + // TODO: Remove this function. It's only used in world/ in a really ugly way.To + // do this properly assets should have all their necessary data in one file. A + // ron file could be used to combine voxel data with positioning data for + // example. + /// Function used to load assets from the filesystem or the cache. Permits + /// manipulating the loaded asset with a mapping function. Example usage: + /// ```no_run + /// use vek::*; + /// use veloren_common::{assets::Asset, terrain::Structure}; + /// + /// let my_tree_structure = Structure::load_map("world.tree.oak_green.1", |s: Structure| { + /// s.with_center(Vec3::new(15, 18, 14)) + /// }) + /// .unwrap(); + /// ``` + fn load_map Self::Output>( + specifier: &str, + f: F, + ) -> Result, Error> + where + Self::Output: Send + Sync + 'static, + { + let assets_write = ASSETS.read().unwrap(); + match assets_write.get(specifier) { + Some(asset) => Ok(Arc::clone(asset).downcast()?), + None => { + drop(assets_write); // Drop the asset hashmap to permit recursive loading + let asset = Arc::new(f(Self::parse(load_file(specifier, Self::ENDINGS)?)?)); + let clone = Arc::clone(&asset); + ASSETS.write().unwrap().insert(specifier.to_owned(), clone); + Ok(asset) + }, + } + } + + fn load_glob(specifier: &str) -> Result>>, Error> + where + Self::Output: Send + Sync + 'static, + { + if let Some(assets) = ASSETS.read().unwrap().get(specifier) { + return Ok(Arc::clone(assets).downcast()?); + } + + // Get glob matches + let glob_matches = read_dir(specifier.trim_end_matches(".*")).map(|dir| { + dir.filter_map(|direntry| { + direntry.ok().and_then(|file| { + file.file_name() + .to_string_lossy() + .rsplitn(2, '.') + .last() + .map(|s| s.to_owned()) + }) + }) + .collect::>() + }); + + match glob_matches { + Ok(glob_matches) => { + let assets = Arc::new( + glob_matches + .into_iter() + .filter_map(|name| { + Self::load(&specifier.replace("*", &name)) + .map_err(|e| { + error!( + ?e, + "Failed to load \"{}\" as part of glob \"{}\"", + name, + specifier + ) + }) + .ok() + }) + .collect::>(), + ); + let clone = Arc::clone(&assets); + + let mut assets_write = ASSETS.write().unwrap(); + assets_write.insert(specifier.to_owned(), clone); + Ok(assets) + }, + Err(error) => Err(error), + } + } + + /// Function used to load assets from the filesystem or the cache. + /// Example usage: + /// ```no_run + /// use image::DynamicImage; + /// use veloren_common::assets::Asset; + /// + /// let my_image = DynamicImage::load("core.ui.backgrounds.city").unwrap(); + /// ``` + fn load(specifier: &str) -> Result, Error> + where + Self::Output: Send + Sync + 'static, + { + Self::load_map(specifier, |x| x) + } + + /// Function used to load assets from the filesystem or the cache and return + /// a clone. + fn load_cloned(specifier: &str) -> Result + where + Self::Output: Clone + Send + Sync + 'static, + { + Self::load(specifier).map(|asset| (*asset).clone()) + } + + /// 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 + /// use image::DynamicImage; + /// use veloren_common::assets::Asset; + /// + /// let my_image = DynamicImage::load_expect("core.ui.backgrounds.city"); + /// ``` + fn load_expect(specifier: &str) -> Arc + where + Self::Output: Send + Sync + 'static, + { + Self::load(specifier).unwrap_or_else(|err| { + panic!( + "Failed loading essential asset: {} (error={:?})", + specifier, err + ) + }) + } + + /// Function used to load essential assets from the filesystem or the cache + /// and return a clone. It will panic if the asset is not found. + fn load_expect_cloned(specifier: &str) -> Self::Output + where + Self::Output: Clone + Send + Sync + 'static, + { + Self::load_expect(specifier).as_ref().clone() + } + + /// Load an asset while registering it to be watched and reloaded when it + /// changes + fn load_watched( + specifier: &str, + indicator: &mut watch::ReloadIndicator, + ) -> Result, Error> + where + Self::Output: Send + Sync + 'static, + { + let asset = Self::load(specifier)?; + + // Determine path to watch + let path = unpack_specifier(specifier); + let mut path_with_extension = None; + for ending in Self::ENDINGS { + let mut path = path.clone(); + path.set_extension(ending); + + if path.exists() { + path_with_extension = Some(path); + break; + } + } + + let owned_specifier = specifier.to_string(); + indicator.add( + path_with_extension + .ok_or_else(|| Error::NotFound(path.to_string_lossy().into_owned()))?, + move || { + if let Err(e) = reload::(&owned_specifier) { + error!(?e, ?owned_specifier, "Error reloading owned_specifier"); + } + }, + ); + + Ok(asset) + } } impl Asset for DynamicImage { @@ -265,13 +293,45 @@ impl Asset for Value { } } -impl Asset for String { - const ENDINGS: &'static [&'static str] = &["glsl"]; +/// Load fron an arbitrary RON file. +pub struct Ron(pub PhantomData); - fn parse(mut buf_reader: BufReader) -> Result { - let mut string = String::new(); - buf_reader.read_to_string(&mut string)?; - Ok(string) +impl Deserialize<'de>> Asset for Ron { + type Output = T; + + const ENDINGS: &'static [&'static str] = &["ron"]; + + fn parse(buf_reader: BufReader) -> Result { + ron::de::from_reader(buf_reader).map_err(Error::parse_error) + } +} + +/// Load from a specific asset path. +pub struct AssetWith { + pub asset: Arc, +} + +impl Clone for AssetWith { + fn clone(&self) -> Self { + Self { + asset: Arc::clone(&self.asset), + } + } +} + +impl AssetWith +where + T::Output: Send + Sync + 'static, +{ + #[inline] + pub fn load_watched(indicator: &mut watch::ReloadIndicator) -> Result { + T::load_watched(ASSET_PATH, indicator).map(|asset| Self { asset }) + } + + #[inline] + pub fn reload(&mut self) -> Result<(), Error> { + self.asset = T::load(ASSET_PATH)?; + Ok(()) } } diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index b786d7d47c..c8eee66e91 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -5,7 +5,7 @@ pub mod tool; pub use tool::{Hands, Tool, ToolCategory, ToolKind}; use crate::{ - assets::{self, Asset}, + assets::{self, Asset, Ron}, effect::Effect, lottery::Lottery, terrain::{Block, BlockKind}, @@ -14,7 +14,6 @@ use rand::prelude::*; use serde::{Deserialize, Serialize}; use specs::{Component, FlaggedStorage}; use specs_idvs::IdvStorage; -use std::{fs::File, io::BufReader}; use vek::Rgb; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -90,13 +89,7 @@ pub struct Item { pub kind: ItemKind, } -impl Asset for Item { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +pub type ItemAsset = Ron; impl Item { // TODO: consider alternatives such as default abilities that can be added to a @@ -109,7 +102,7 @@ impl Item { } } - pub fn expect_from_asset(asset: &str) -> Self { (*assets::load_expect::(asset)).clone() } + pub fn expect_from_asset(asset: &str) -> Self { (*ItemAsset::load_expect(asset)).clone() } pub fn set_amount(&mut self, give_amount: u32) -> Result<(), assets::Error> { use ItemKind::*; @@ -145,75 +138,44 @@ impl Item { } pub fn try_reclaim_from_block(block: Block) -> Option { + let chosen; let mut rng = rand::thread_rng(); - match block.kind() { - BlockKind::Apple => Some(assets::load_expect_cloned("common.items.food.apple")), - BlockKind::Mushroom => Some(assets::load_expect_cloned("common.items.food.mushroom")), - BlockKind::Velorite => Some(assets::load_expect_cloned("common.items.ore.velorite")), - BlockKind::VeloriteFrag => { - Some(assets::load_expect_cloned("common.items.ore.veloritefrag")) - }, - BlockKind::BlueFlower => Some(assets::load_expect_cloned("common.items.flowers.blue")), - BlockKind::PinkFlower => Some(assets::load_expect_cloned("common.items.flowers.pink")), - BlockKind::PurpleFlower => { - Some(assets::load_expect_cloned("common.items.flowers.purple")) - }, - BlockKind::RedFlower => Some(assets::load_expect_cloned("common.items.flowers.red")), - BlockKind::WhiteFlower => { - Some(assets::load_expect_cloned("common.items.flowers.white")) - }, - BlockKind::YellowFlower => { - Some(assets::load_expect_cloned("common.items.flowers.yellow")) - }, - BlockKind::Sunflower => Some(assets::load_expect_cloned("common.items.flowers.sun")), - BlockKind::LongGrass => Some(assets::load_expect_cloned("common.items.grasses.long")), - BlockKind::MediumGrass => { - Some(assets::load_expect_cloned("common.items.grasses.medium")) - }, - BlockKind::ShortGrass => Some(assets::load_expect_cloned("common.items.grasses.short")), - BlockKind::Coconut => Some(assets::load_expect_cloned("common.items.food.coconut")), + Some(ItemAsset::load_expect_cloned(match block.kind() { + BlockKind::Apple => "common.items.food.apple", + BlockKind::Mushroom => "common.items.food.mushroom", + BlockKind::Velorite => "common.items.ore.velorite", + BlockKind::VeloriteFrag => "common.items.ore.veloritefrag", + BlockKind::BlueFlower => "common.items.flowers.blue", + BlockKind::PinkFlower => "common.items.flowers.pink", + BlockKind::PurpleFlower => "common.items.flowers.purple", + BlockKind::RedFlower => "common.items.flowers.red", + BlockKind::WhiteFlower => "common.items.flowers.white", + BlockKind::YellowFlower => "common.items.flowers.yellow", + BlockKind::Sunflower => "common.items.flowers.sun", + BlockKind::LongGrass => "common.items.grasses.long", + BlockKind::MediumGrass => "common.items.grasses.medium", + BlockKind::ShortGrass => "common.items.grasses.short", + BlockKind::Coconut => "common.items.food.coconut", BlockKind::Chest => { - let chosen = match rng.gen_range(0, 7) { - 0 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_uncommon", - ), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_common", - ), - 2 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_light", - ), - 3 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_cloth", - ), - 4 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_heavy", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - }; - let chosen = chosen.choose(); - Some(assets::load_expect_cloned(chosen)) + chosen = Lottery::::load_expect(match rng.gen_range(0, 7) { + 0 => "common.loot_tables.loot_table_weapon_uncommon", + 1 => "common.loot_tables.loot_table_weapon_common", + 2 => "common.loot_tables.loot_table_armor_light", + 3 => "common.loot_tables.loot_table_armor_cloth", + 4 => "common.loot_tables.loot_table_armor_heavy", + _ => "common.loot_tables.loot_table_armor_misc", + }); + chosen.choose() }, BlockKind::Crate => { - let chosen = - assets::load_expect::>("common.loot_tables.loot_table_food"); - let chosen = chosen.choose(); - - Some(assets::load_expect_cloned(chosen)) + chosen = Lottery::::load_expect("common.loot_tables.loot_table_food"); + chosen.choose() }, - BlockKind::Stones => Some(assets::load_expect_cloned( - "common.items.crafting_ing.stones", - )), - BlockKind::Twigs => Some(assets::load_expect_cloned( - "common.items.crafting_ing.twigs", - )), - BlockKind::ShinyGem => Some(assets::load_expect_cloned( - "common.items.crafting_ing.shiny_gem", - )), - _ => None, - } + BlockKind::Stones => "common.items.crafting_ing.stones", + BlockKind::Twigs => "common.items.crafting_ing.twigs", + BlockKind::ShinyGem => "common.items.crafting_ing.shiny_gem", + _ => return None, + })) } /// Determines whether two items are superficially equivalent to one another diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index b0204eb60c..db5baf3541 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -1,8 +1,8 @@ pub mod item; pub mod slot; -use crate::{assets, recipe::Recipe}; -use item::{Item, ItemKind}; +use crate::{assets::Asset, recipe::Recipe}; +use item::{Item, ItemAsset, ItemKind}; use serde::{Deserialize, Serialize}; use specs::{Component, FlaggedStorage, HashMapStorage}; use specs_idvs::IdvStorage; @@ -517,8 +517,8 @@ impl Default for Inventory { slots: vec![None; 36], amount: 0, }; - inventory.push(assets::load_expect_cloned("common.items.food.cheese")); - inventory.push(assets::load_expect_cloned("common.items.food.apple")); + inventory.push(ItemAsset::load_expect_cloned("common.items.food.cheese")); + inventory.push(ItemAsset::load_expect_cloned("common.items.food.apple")); inventory } } diff --git a/common/src/comp/inventory/slot.rs b/common/src/comp/inventory/slot.rs index 9aa2eb6389..bcf380d5a4 100644 --- a/common/src/comp/inventory/slot.rs +++ b/common/src/comp/inventory/slot.rs @@ -266,15 +266,16 @@ pub fn swap( /// /// ``` /// use veloren_common::{ -/// assets, +/// assets::Asset, /// comp::{ +/// item::ItemAsset, /// slot::{equip, EquipSlot}, /// Inventory, Item, /// }, /// LoadoutBuilder, /// }; /// -/// let boots: Option = Some(assets::load_expect_cloned( +/// let boots: Option = Some(ItemAsset::load_expect_cloned( /// "common.items.testing.test_boots", /// )); /// @@ -361,7 +362,7 @@ pub fn unequip(slot: EquipSlot, inventory: &mut Inventory, loadout: &mut Loadout #[cfg(test)] mod tests { use super::*; - use crate::{assets, LoadoutBuilder}; + use crate::{assets::Asset, comp::item::ItemAsset, LoadoutBuilder}; #[test] fn test_unequip_items_both_hands() { @@ -396,11 +397,11 @@ mod tests { #[test] fn test_equip_item() { - let boots: Option = Some(assets::load_expect_cloned( + let boots: Option = Some(ItemAsset::load_expect_cloned( "common.items.testing.test_boots", )); - let starting_sandles: Option = Some(assets::load_expect_cloned( + let starting_sandles: Option = Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.sandals_0", )); @@ -425,11 +426,11 @@ mod tests { #[test] fn test_loadout_replace() { - let boots: Option = Some(assets::load_expect_cloned( + let boots: Option = Some(ItemAsset::load_expect_cloned( "common.items.testing.test_boots", )); - let starting_sandles: Option = Some(assets::load_expect_cloned( + let starting_sandles: Option = Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.sandals_0", )); diff --git a/common/src/comp/inventory/test.rs b/common/src/comp/inventory/test.rs index ac782b9b27..e27bdf9274 100644 --- a/common/src/comp/inventory/test.rs +++ b/common/src/comp/inventory/test.rs @@ -1,9 +1,10 @@ use super::*; +use crate::assets::Asset; use lazy_static::lazy_static; lazy_static! { static ref TEST_ITEMS: Vec = vec![ - assets::load_expect_cloned("common.items.debug.boost"), - assets::load_expect_cloned("common.items.debug.possess") + item::ItemAsset::load_expect_cloned("common.items.debug.boost"), + item::ItemAsset::load_expect_cloned("common.items.debug.possess") ]; } diff --git a/common/src/lib.rs b/common/src/lib.rs index dacdedd767..89abe44963 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,9 +1,12 @@ #![deny(unsafe_code)] #![allow(clippy::option_map_unit_fn)] +#![allow(incomplete_features)] #![type_length_limit = "1664759"] #![feature( arbitrary_enum_discriminant, + associated_type_defaults, const_checked_int_methods, + const_generics, fundamental, option_unwrap_none, bool_to_option, diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 441b493cd8..968e648ff7 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -1,7 +1,7 @@ use crate::{ - assets, + assets::Asset, comp::{ - item::{Item, ItemKind}, + item::{Item, ItemAsset, ItemKind}, Body, CharacterAbility, ItemConfig, Loadout, }, }; @@ -48,16 +48,16 @@ impl LoadoutBuilder { /// Set default armor items for the loadout. This may vary with game /// updates, but should be safe defaults for a new character. pub fn defaults(self) -> Self { - self.chest(Some(assets::load_expect_cloned( + self.chest(Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.rugged_chest", ))) - .pants(Some(assets::load_expect_cloned( + .pants(Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.rugged_pants", ))) - .foot(Some(assets::load_expect_cloned( + .foot(Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.sandals_0", ))) - .lantern(Some(assets::load_expect_cloned( + .lantern(Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.lantern", ))) } @@ -66,7 +66,7 @@ impl LoadoutBuilder { pub fn animal(body: Body) -> Self { Self(Loadout { active_item: Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.empty.empty"), + item: ItemAsset::load_expect_cloned("common.items.weapons.empty.empty"), ability1: Some(CharacterAbility::BasicMelee { energy_cost: 10, buildup_duration: Duration::from_millis(600), @@ -125,7 +125,7 @@ impl LoadoutBuilder { /// Get an [Item](../comp/struct.Item.html) by its string /// reference by loading its asset pub fn item_from_str(item_ref: Option<&str>) -> Option { - item_ref.and_then(|specifier| assets::load_cloned::(&specifier).ok()) + item_ref.and_then(|specifier| ItemAsset::load_cloned(&specifier).ok()) } /// Get an item's (weapon's) default diff --git a/common/src/lottery.rs b/common/src/lottery.rs index f25a5966b7..423575d62c 100644 --- a/common/src/lottery.rs +++ b/common/src/lottery.rs @@ -1,9 +1,9 @@ use crate::assets::{self, Asset}; use rand::prelude::*; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize}; use std::{fs::File, io::BufReader}; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Deserialize)] pub struct Lottery { items: Vec<(f32, T)>, total: f32, @@ -48,14 +48,14 @@ impl Lottery { #[cfg(test)] mod tests { use super::*; - use crate::{assets, comp::Item}; + use crate::comp::item::ItemAsset; #[test] fn test_loot_table() { - let test = assets::load_expect::>("common.loot_tables.loot_table"); + let test = Lottery::::load_expect("common.loot_tables.loot_table"); for (_, item) in test.iter() { assert!( - assets::load::(item).is_ok(), + ItemAsset::load(item).is_ok(), "Invalid loot table item '{}'", item ); diff --git a/common/src/npc.rs b/common/src/npc.rs index 445743329f..815aa1e35f 100644 --- a/common/src/npc.rs +++ b/common/src/npc.rs @@ -1,5 +1,5 @@ use crate::{ - assets, + assets::Asset, comp::{self, AllBodies, Body}, }; use lazy_static::lazy_static; @@ -63,7 +63,7 @@ pub struct SpeciesNames { pub type NpcNames = AllBodies; lazy_static! { - pub static ref NPC_NAMES: Arc = assets::load_expect("common.npc_names"); + pub static ref NPC_NAMES: Arc = NpcNames::load_expect("common.npc_names"); } impl FromStr for NpcKind { diff --git a/common/src/recipe.rs b/common/src/recipe.rs index bad5a81abf..5bf7c7d3fd 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -1,6 +1,6 @@ use crate::{ assets::{self, Asset}, - comp::{Inventory, Item}, + comp::{item::ItemAsset, Inventory, Item}, }; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; @@ -78,12 +78,12 @@ impl Asset for RecipeBook { .map::, _>( |(name, ((output, amount), inputs))| { Ok((name, Recipe { - output: ((&*assets::load::(&output)?).clone(), amount), + output: ((&*ItemAsset::load(&output)?).clone(), amount), inputs: inputs .into_iter() .map::, _>( |(name, amount)| { - Ok(((&*assets::load::(&name)?).clone(), amount)) + Ok(((&*ItemAsset::load(&name)?).clone(), amount)) }, ) .collect::>()?, @@ -96,4 +96,4 @@ impl Asset for RecipeBook { } } -pub fn default_recipe_book() -> Arc { assets::load_expect("common.recipe_book") } +pub fn default_recipe_book() -> Arc { RecipeBook::load_expect("common.recipe_book") } diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index abe9168f4f..5401cf7267 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -1,6 +1,6 @@ use super::BlockKind; use crate::{ - assets::{self, Asset}, + assets::{self, Asset, Ron}, make_case_elim, vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}, volumes::dyna::{Dyna, DynaError}, @@ -53,15 +53,11 @@ pub struct Structure { impl Structure { pub fn load_group(specifier: &str) -> Vec> { - let spec = assets::load::(&["world.manifests.", specifier].concat()); - spec.unwrap() - .0 - .iter() + let spec = StructuresSpec::load_expect(&["world.manifests.", specifier].concat()); + spec.iter() .map(|sp| { - assets::load_map(&sp.specifier[..], |s: Structure| { - s.with_center(Vec3::from(sp.center)) - }) - .unwrap() + Structure::load_map(&sp.specifier[..], |s| s.with_center(Vec3::from(sp.center))) + .unwrap() }) .collect() } @@ -170,13 +166,5 @@ struct StructureSpec { specifier: String, center: [i32; 3], } -#[derive(Deserialize)] -struct StructuresSpec(Vec); -impl Asset for StructuresSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +type StructuresSpec = Ron>; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index e3a836c471..0fcf7cf612 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -5,9 +5,9 @@ use crate::{client::Client, Server, StateExt}; use chrono::{NaiveTime, Timelike}; use common::{ - assets, + assets::Asset, cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS}, - comp::{self, ChatType, Item, LightEmitter, WaypointArea}, + comp::{self, item::ItemAsset, ChatType, Item, LightEmitter, WaypointArea}, event::{EventBus, ServerEvent}, msg::{Notification, PlayerListUpdate, ServerMsg}, npc::{self, get_npc_name}, @@ -117,7 +117,7 @@ fn handle_give_item( scan_fmt_some!(&args, &action.arg_fmt(), String, u32) { let give_amount = give_amount_opt.unwrap_or(1); - if let Ok(item) = assets::load_cloned(&item_name) { + if let Ok(item) = ItemAsset::load_cloned(&item_name) { let mut item: Item = item; if let Ok(()) = item.set_amount(give_amount.min(2000)) { server @@ -1640,7 +1640,7 @@ fn handle_debug( _args: String, _action: &ChatCommand, ) { - if let Ok(items) = assets::load_glob::("common.items.debug.*") { + if let Ok(items) = ItemAsset::load_glob("common.items.debug.*") { server .state() .ecs() diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index ccd0ca47eb..c9a0032b55 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -1,9 +1,9 @@ use crate::{client::Client, comp::quadruped_small, Server, SpawnPoint, StateExt}; use common::{ - assets, + assets::Asset, comp::{ - self, object, Alignment, Body, Damage, DamageSource, Group, HealthChange, HealthSource, - Player, Pos, Stats, + self, item::ItemAsset, object, Alignment, Body, Damage, DamageSource, Group, HealthChange, + HealthSource, Player, Pos, Stats, }, lottery::Lottery, msg::{PlayerListUpdate, ServerMsg}, @@ -186,130 +186,68 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc // Decide for a loot drop before turning into a lootbag let old_body = state.ecs().write_storage::().remove(entity); let mut rng = rand::thread_rng(); - let drop = match old_body { + let drop = Lottery::::load_expect(match old_body { Some(common::comp::Body::Humanoid(_)) => match rng.gen_range(0, 4) { - 0 => assets::load_expect::>( - "common.loot_tables.loot_table_humanoids", - ), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_light", - ), - 2 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_cloth", - ), - 3 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_common", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_humanoids", - ), + 0 => "common.loot_tables.loot_table_humanoids", + 1 => "common.loot_tables.loot_table_armor_light", + 2 => "common.loot_tables.loot_table_armor_cloth", + 3 => "common.loot_tables.loot_table_weapon_common", + _ => "common.loot_tables.loot_table_humanoids", }, Some(common::comp::Body::QuadrupedSmall(quadruped_small)) => { match quadruped_small.species { quadruped_small::Species::Dodarock => match rng.gen_range(0, 6) { - 0 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_rocks", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_rocks", - ), + 0 => "common.loot_tables.loot_table_armor_misc", + 1 => "common.loot_tables.loot_table_rocks", + _ => "common.loot_tables.loot_table_rocks", }, _ => match rng.gen_range(0, 4) { - 0 => assets::load_expect::>( - "common.loot_tables.loot_table_food", - ), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - 2 => assets::load_expect::>( - "common.loot_tables.loot_table_animal_parts", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_animal_parts", - ), + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_armor_misc", + 2 => "common.loot_tables.loot_table_animal_parts", + _ => "common.loot_tables.loot_table_animal_parts", }, } }, Some(common::comp::Body::QuadrupedMedium(_)) => match rng.gen_range(0, 4) { - 0 => assets::load_expect::>("common.loot_tables.loot_table_food"), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - 2 => assets::load_expect::>( - "common.loot_tables.loot_table_animal_parts", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_animal_parts", - ), + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_armor_misc", + 2 => "common.loot_tables.loot_table_animal_parts", + _ => "common.loot_tables.loot_table_animal_parts", }, Some(common::comp::Body::BirdMedium(_)) => match rng.gen_range(0, 3) { - 0 => assets::load_expect::>("common.loot_tables.loot_table_food"), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - _ => assets::load_expect::>("common.loot_tables.loot_table"), + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_armor_misc", + _ => "common.loot_tables.loot_table", }, Some(common::comp::Body::BipedLarge(_)) => match rng.gen_range(0, 8) { - 0 => assets::load_expect::>("common.loot_tables.loot_table_food"), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_nature", - ), - 3 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_heavy", - ), - 5 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_uncommon", - ), - 6 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_rare", - ), - _ => assets::load_expect::>( - "common.loot_tables.loot_table_cave_large", - ), + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_armor_nature", + 3 => "common.loot_tables.loot_table_armor_heavy", + 5 => "common.loot_tables.loot_table_weapon_uncommon", + 6 => "common.loot_tables.loot_table_weapon_rare", + _ => "common.loot_tables.loot_table_cave_large", }, Some(common::comp::Body::Golem(_)) => match rng.gen_range(0, 9) { - 0 => assets::load_expect::>("common.loot_tables.loot_table_food"), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - 2 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_light", - ), - 3 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_heavy", - ), - 4 => assets::load_expect::>( - "common.loot_tables.loot_table_armor_misc", - ), - 5 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_common", - ), - 6 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_uncommon", - ), - 7 => assets::load_expect::>( - "common.loot_tables.loot_table_weapon_rare", - ), - _ => assets::load_expect::>("common.loot_tables.loot_table"), - }, - Some(common::comp::Body::Critter(_)) => { - assets::load_expect::>("common.loot_tables.loot_table_animal_parts") - }, - Some(common::comp::Body::Dragon(_)) => { - assets::load_expect::>("common.loot_tables.loot_table_weapon_rare") + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_armor_misc", + 2 => "common.loot_tables.loot_table_armor_light", + 3 => "common.loot_tables.loot_table_armor_heavy", + 4 => "common.loot_tables.loot_table_armor_misc", + 5 => "common.loot_tables.loot_table_weapon_common", + 6 => "common.loot_tables.loot_table_weapon_uncommon", + 7 => "common.loot_tables.loot_table_weapon_rare", + _ => "common.loot_tables.loot_table", }, + Some(common::comp::Body::Critter(_)) => "common.loot_tables.loot_table_animal_parts", + Some(common::comp::Body::Dragon(_)) => "common.loot_tables.loot_table_weapon_rare", Some(common::comp::Body::QuadrupedLow(_)) => match rng.gen_range(0, 3) { - 0 => assets::load_expect::>("common.loot_tables.loot_table_food"), - 1 => assets::load_expect::>( - "common.loot_tables.loot_table_animal_parts", - ), - _ => assets::load_expect::>("common.loot_tables.loot_table"), + 0 => "common.loot_tables.loot_table_food", + 1 => "common.loot_tables.loot_table_animal_parts", + _ => "common.loot_tables.loot_table", }, - _ => assets::load_expect::>("common.loot_tables.loot_table"), - }; + _ => "common.loot_tables.loot_table", + }); let drop = drop.choose(); // Replace npc with lootbag containing drop let _ = state @@ -321,7 +259,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc item_drops.remove(entity); item_drop.0 } else { - assets::load_expect_cloned(drop) + ItemAsset::load_expect_cloned(drop) }; let _ = state.ecs().write_storage().insert(entity, item); diff --git a/server/src/events/interaction.rs b/server/src/events/interaction.rs index 04b92ae292..3aba3e1b17 100644 --- a/server/src/events/interaction.rs +++ b/server/src/events/interaction.rs @@ -3,7 +3,7 @@ use crate::{ Server, }; use common::{ - assets, + assets::Asset, comp::{self, item}, msg::ServerMsg, sync::{Uid, WorldSyncExt}, @@ -125,7 +125,7 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) { .expect("Could not read loadouts component while possessing") .or_insert(comp::Loadout::default()); - let item = assets::load_expect_cloned::("common.items.debug.possess"); + let item = item::ItemAsset::load_expect_cloned("common.items.debug.possess"); if let item::ItemKind::Tool(tool) = &item.kind { let mut abilities = tool.get_abilities(); let mut ability_drain = abilities.drain(..); diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 4fa2559fdb..2270807410 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -1,8 +1,12 @@ use super::SysTimer; use crate::{chunk_generator::ChunkGenerator, client::Client, Tick}; use common::{ - assets, - comp::{self, bird_medium, item, Alignment, CharacterAbility, ItemConfig, Player, Pos}, + assets::Asset, + comp::{ + self, bird_medium, + item::{self, ItemAsset}, + Alignment, CharacterAbility, ItemConfig, Player, Pos, + }, event::{EventBus, ServerEvent}, generation::get_npc_name, msg::ServerMsg, @@ -135,7 +139,7 @@ impl<'a> System<'a> for Sys { } else { Some(ItemConfig { // We need the empty item so npcs can attack - item: assets::load_expect_cloned("common.items.weapons.empty.empty"), + item: ItemAsset::load_expect_cloned("common.items.weapons.empty.empty"), ability1: Some(CharacterAbility::BasicMelee { energy_cost: 0, buildup_duration: Duration::from_millis(0), @@ -156,7 +160,7 @@ impl<'a> System<'a> for Sys { active_item, second_item: None, shoulder: None, - chest: Some(assets::load_expect_cloned( + chest: Some(ItemAsset::load_expect_cloned( match rand::thread_rng().gen_range(0, 10) { 0 => "common.items.npc_armor.chest.worker_green_0", 1 => "common.items.npc_armor.chest.worker_green_1", @@ -170,14 +174,14 @@ impl<'a> System<'a> for Sys { _ => "common.items.npc_armor.chest.worker_orange_1", }, )), - belt: Some(assets::load_expect_cloned( + belt: Some(ItemAsset::load_expect_cloned( "common.items.armor.belt.leather_0", )), hand: None, - pants: Some(assets::load_expect_cloned( + pants: Some(ItemAsset::load_expect_cloned( "common.items.armor.pants.worker_blue_0", )), - foot: Some(assets::load_expect_cloned( + foot: Some(ItemAsset::load_expect_cloned( match rand::thread_rng().gen_range(0, 2) { 0 => "common.items.armor.foot.leather_0", _ => "common.items.armor.starter.sandals_0", @@ -193,30 +197,32 @@ impl<'a> System<'a> for Sys { comp::Alignment::Enemy => comp::Loadout { active_item, second_item: None, - shoulder: Some(assets::load_expect_cloned( + shoulder: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.shoulder.cultist_shoulder_purple", )), - chest: Some(assets::load_expect_cloned( + chest: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.chest.cultist_chest_purple", )), - belt: Some(assets::load_expect_cloned( + belt: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.belt.cultist_belt", )), - hand: Some(assets::load_expect_cloned( + hand: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.hand.cultist_hands_purple", )), - pants: Some(assets::load_expect_cloned( + pants: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.pants.cultist_legs_purple", )), - foot: Some(assets::load_expect_cloned( + foot: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.foot.cultist_boots", )), - back: Some(assets::load_expect_cloned( + back: Some(ItemAsset::load_expect_cloned( "common.items.npc_armor.back.dungeon_purple-0", )), ring: None, neck: None, - lantern: Some(assets::load_expect_cloned("common.items.lantern.black_0")), + lantern: Some(ItemAsset::load_expect_cloned( + "common.items.lantern.black_0", + )), head: None, tabard: None, }, @@ -259,7 +265,7 @@ impl<'a> System<'a> for Sys { } loadout = comp::Loadout { active_item: Some(comp::ItemConfig { - item: assets::load_expect_cloned( + item: ItemAsset::load_expect_cloned( "common.items.npc_weapons.sword.zweihander_sword_0", ), ability1: Some(CharacterAbility::BasicMelee { @@ -276,22 +282,22 @@ impl<'a> System<'a> for Sys { dodge_ability: None, }), second_item: None, - shoulder: Some(assets::load_expect_cloned( + shoulder: Some(ItemAsset::load_expect_cloned( "common.items.armor.shoulder.plate_0", )), - chest: Some(assets::load_expect_cloned( + chest: Some(ItemAsset::load_expect_cloned( "common.items.armor.chest.plate_green_0", )), - belt: Some(assets::load_expect_cloned( + belt: Some(ItemAsset::load_expect_cloned( "common.items.armor.belt.plate_0", )), - hand: Some(assets::load_expect_cloned( + hand: Some(ItemAsset::load_expect_cloned( "common.items.armor.hand.plate_0", )), - pants: Some(assets::load_expect_cloned( + pants: Some(ItemAsset::load_expect_cloned( "common.items.armor.pants.plate_green_0", )), - foot: Some(assets::load_expect_cloned( + foot: Some(ItemAsset::load_expect_cloned( "common.items.armor.foot.plate_0", )), back: None, diff --git a/tools/src/main.rs b/tools/src/main.rs index 441226b756..d16089f00d 100644 --- a/tools/src/main.rs +++ b/tools/src/main.rs @@ -5,10 +5,14 @@ use std::{ }; use structopt::StructOpt; -use common::{assets, comp}; +use common::{ + assets::{self, Asset}, + comp, +}; use comp::item::{ armor::{ArmorKind, Protection}, tool::ToolKind, + ItemAsset, }; #[derive(StructOpt)] @@ -43,7 +47,7 @@ fn armor_stats() -> Result<(), Box> { .to_string() .replace("/", "."); - let asset = assets::load_expect_cloned::(asset_identifier); + let asset = ItemAsset::load_expect_cloned(asset_identifier); match &asset.kind { comp::item::ItemKind::Armor(armor) => { @@ -109,7 +113,7 @@ fn weapon_stats() -> Result<(), Box> { .display() .to_string() .replace("/", "."); - let asset = assets::load_expect_cloned::(asset_identifier); + let asset = ItemAsset::load_expect_cloned(asset_identifier); match &asset.kind { comp::item::ItemKind::Tool(tool) => { diff --git a/voxygen/src/anim/src/biped_large/mod.rs b/voxygen/src/anim/src/biped_large/mod.rs index e812e0cd8b..48706272a4 100644 --- a/voxygen/src/anim/src/biped_large/mod.rs +++ b/voxygen/src/anim/src/biped_large/mod.rs @@ -10,10 +10,12 @@ pub use self::{ wield::WieldAnimation, }; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::biped_large::Body; + skeleton_impls!(struct BipedLargeSkeleton { + head, + jaw, @@ -36,6 +38,7 @@ skeleton_impls!(struct BipedLargeSkeleton { impl Skeleton for BipedLargeSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 15; #[cfg(feature = "use-dyn-lib")] @@ -115,8 +118,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::biped_large::Body> for SkeletonAttr { - fn from(body: &'a comp::biped_large::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::biped_large::{BodyType::*, Species::*}; Self { head: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/bird_medium/mod.rs b/voxygen/src/anim/src/bird_medium/mod.rs index 09096ab094..9f969f47a7 100644 --- a/voxygen/src/anim/src/bird_medium/mod.rs +++ b/voxygen/src/anim/src/bird_medium/mod.rs @@ -6,10 +6,12 @@ pub mod run; // Reexports pub use self::{feed::FeedAnimation, fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::bird_medium::Body; + skeleton_impls!(struct BirdMediumSkeleton { + head, + torso, @@ -22,6 +24,7 @@ skeleton_impls!(struct BirdMediumSkeleton { impl Skeleton for BirdMediumSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 7; #[cfg(feature = "use-dyn-lib")] @@ -82,8 +85,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::bird_medium::Body> for SkeletonAttr { - fn from(body: &'a comp::bird_medium::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::bird_medium::Species::*; Self { head: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/bird_small/mod.rs b/voxygen/src/anim/src/bird_small/mod.rs index 3684e6d977..b5ffa053a5 100644 --- a/voxygen/src/anim/src/bird_small/mod.rs +++ b/voxygen/src/anim/src/bird_small/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::bird_small::Body; + skeleton_impls!(struct BirdSmallSkeleton { + head, + torso, @@ -18,6 +20,7 @@ skeleton_impls!(struct BirdSmallSkeleton { impl Skeleton for BirdSmallSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 4; #[cfg(feature = "use-dyn-lib")] @@ -59,6 +62,6 @@ impl Default for SkeletonAttr { fn default() -> Self { Self } } -impl<'a> From<&'a comp::bird_small::Body> for SkeletonAttr { - fn from(_body: &'a comp::bird_small::Body) -> Self { Self } +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(_body: &'a Body) -> Self { Self } } diff --git a/voxygen/src/anim/src/character/mod.rs b/voxygen/src/anim/src/character/mod.rs index 4709eac25b..7445013b44 100644 --- a/voxygen/src/anim/src/character/mod.rs +++ b/voxygen/src/anim/src/character/mod.rs @@ -36,10 +36,12 @@ pub use self::{ swimwield::SwimWieldAnimation, wield::WieldAnimation, }; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp; use core::convert::TryFrom; +pub type Body = comp::humanoid::Body; + skeleton_impls!(struct CharacterSkeleton { + head, + chest, @@ -65,6 +67,7 @@ skeleton_impls!(struct CharacterSkeleton { impl Skeleton for CharacterSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 16; #[cfg(feature = "use-dyn-lib")] @@ -156,7 +159,7 @@ impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr { } impl SkeletonAttr { - pub fn calculate_scale(body: &comp::humanoid::Body) -> f32 { + pub fn calculate_scale(body: &Body) -> f32 { use comp::humanoid::{BodyType::*, Species::*}; match (body.species, body.body_type) { (Orc, Male) => 1.14, @@ -175,9 +178,9 @@ impl SkeletonAttr { } } -impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr { +impl<'a> From<&'a Body> for SkeletonAttr { #[allow(clippy::match_single_binding)] // TODO: Pending review in #587 - fn from(body: &'a comp::humanoid::Body) -> Self { + fn from(body: &'a Body) -> Self { use comp::humanoid::{BodyType::*, Species::*}; Self { scaler: SkeletonAttr::calculate_scale(body), diff --git a/voxygen/src/anim/src/critter/mod.rs b/voxygen/src/anim/src/critter/mod.rs index 5e50de56cc..f83461a23b 100644 --- a/voxygen/src/anim/src/critter/mod.rs +++ b/voxygen/src/anim/src/critter/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::critter::Body; + skeleton_impls!(struct CritterSkeleton { + head, + chest, @@ -27,6 +29,7 @@ pub struct CritterAttr { impl Skeleton for CritterSkeleton { type Attr = CritterAttr; + type Body = Body; const BONE_COUNT: usize = 5; #[cfg(feature = "use-dyn-lib")] @@ -84,8 +87,8 @@ impl Default for CritterAttr { } } -impl<'a> From<&'a comp::critter::Body> for CritterAttr { - fn from(body: &'a comp::critter::Body) -> Self { +impl<'a> From<&'a Body> for CritterAttr { + fn from(body: &'a Body) -> Self { use comp::critter::Species::*; Self { head: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/dragon/mod.rs b/voxygen/src/anim/src/dragon/mod.rs index 4792a7afdb..9e5d39d200 100644 --- a/voxygen/src/anim/src/dragon/mod.rs +++ b/voxygen/src/anim/src/dragon/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::dragon::Body; + skeleton_impls!(struct DragonSkeleton { + head_upper, + head_lower, @@ -29,6 +31,7 @@ skeleton_impls!(struct DragonSkeleton { impl Skeleton for DragonSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 15; #[cfg(feature = "use-dyn-lib")] @@ -115,8 +118,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::dragon::Body> for SkeletonAttr { - fn from(body: &'a comp::dragon::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::dragon::Species::*; Self { head_upper: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/fish_medium/mod.rs b/voxygen/src/anim/src/fish_medium/mod.rs index 97e663bb97..63b1b7e6b9 100644 --- a/voxygen/src/anim/src/fish_medium/mod.rs +++ b/voxygen/src/anim/src/fish_medium/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::fish_medium::Body; + skeleton_impls!(struct FishMediumSkeleton { + head, + torso, @@ -20,6 +22,7 @@ skeleton_impls!(struct FishMediumSkeleton { impl Skeleton for FishMediumSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 6; #[cfg(feature = "use-dyn-lib")] @@ -63,6 +66,6 @@ impl Default for SkeletonAttr { fn default() -> Self { Self } } -impl<'a> From<&'a comp::fish_medium::Body> for SkeletonAttr { - fn from(_body: &'a comp::fish_medium::Body) -> Self { Self } +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(_body: &'a Body) -> Self { Self } } diff --git a/voxygen/src/anim/src/fish_small/mod.rs b/voxygen/src/anim/src/fish_small/mod.rs index d3281ff459..f055901750 100644 --- a/voxygen/src/anim/src/fish_small/mod.rs +++ b/voxygen/src/anim/src/fish_small/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::fish_small::Body; + skeleton_impls!(struct FishSmallSkeleton { + torso, + tail, @@ -16,6 +18,7 @@ skeleton_impls!(struct FishSmallSkeleton { impl Skeleton for FishSmallSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 2; #[cfg(feature = "use-dyn-lib")] @@ -55,6 +58,6 @@ impl Default for SkeletonAttr { fn default() -> Self { Self } } -impl<'a> From<&'a comp::fish_small::Body> for SkeletonAttr { - fn from(_body: &'a comp::fish_small::Body) -> Self { Self } +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(_body: &'a Body) -> Self { Self } } diff --git a/voxygen/src/anim/src/fixture/mod.rs b/voxygen/src/anim/src/fixture/mod.rs index 633b2a5ec6..edc2c38d80 100644 --- a/voxygen/src/anim/src/fixture/mod.rs +++ b/voxygen/src/anim/src/fixture/mod.rs @@ -1,5 +1,7 @@ use super::{make_bone, vek::*, FigureBoneData, Skeleton}; +pub type Body = (); + #[derive(Clone, Default)] pub struct FixtureSkeleton; @@ -17,6 +19,7 @@ impl<'a, Factor> Lerp for &'a FixtureSkeleton { impl Skeleton for FixtureSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 1; #[cfg(feature = "use-dyn-lib")] @@ -33,3 +36,11 @@ impl Skeleton for FixtureSkeleton { Vec3::default() } } + +impl Default for SkeletonAttr { + fn default() -> Self { Self } +} + +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(_body: &'a Body) -> Self { Self } +} diff --git a/voxygen/src/anim/src/golem/mod.rs b/voxygen/src/anim/src/golem/mod.rs index 015c3d8750..8a39b74dec 100644 --- a/voxygen/src/anim/src/golem/mod.rs +++ b/voxygen/src/anim/src/golem/mod.rs @@ -5,10 +5,12 @@ pub mod run; // Reexports pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::golem::Body; + skeleton_impls!(struct GolemSkeleton { + head, + upper_torso, @@ -25,6 +27,7 @@ skeleton_impls!(struct GolemSkeleton { impl Skeleton for GolemSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 10; #[cfg(feature = "use-dyn-lib")] @@ -90,8 +93,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::golem::Body> for SkeletonAttr { - fn from(body: &'a comp::golem::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::golem::Species::*; Self { head: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/lib.rs b/voxygen/src/anim/src/lib.rs index e12290e9e9..833227ae5f 100644 --- a/voxygen/src/anim/src/lib.rs +++ b/voxygen/src/anim/src/lib.rs @@ -9,14 +9,14 @@ macro_rules! skeleton_impls { #[derive(Clone, Default)] pub struct $Skeleton { $( - $bone: Bone, + $bone: $crate::Bone, )* } - impl<'a, Factor> Lerp for &'a $Skeleton + impl<'a, Factor> $crate::vek::Lerp for &'a $Skeleton where Factor: Copy, - Bone: Lerp + $crate::Bone: Lerp { type Output = $Skeleton; @@ -79,6 +79,7 @@ pub type Bone = Transform; pub trait Skeleton: Send + Sync + 'static { type Attr; + type Body; const BONE_COUNT: usize; diff --git a/voxygen/src/anim/src/object/mod.rs b/voxygen/src/anim/src/object/mod.rs index d0613aa59c..1c1306cba0 100644 --- a/voxygen/src/anim/src/object/mod.rs +++ b/voxygen/src/anim/src/object/mod.rs @@ -1,4 +1,7 @@ use super::{make_bone, vek::*, FigureBoneData, Skeleton}; +use common::comp::{self}; + +pub type Body = comp::object::Body; #[derive(Clone, Default)] pub struct ObjectSkeleton; @@ -19,6 +22,7 @@ const SCALE: f32 = 1.0 / 11.0; impl Skeleton for ObjectSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 1; #[cfg(feature = "use-dyn-lib")] @@ -34,3 +38,11 @@ impl Skeleton for ObjectSkeleton { Vec3::default() } } + +impl Default for SkeletonAttr { + fn default() -> Self { Self } +} + +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(_body: &'a Body) -> Self { Self } +} diff --git a/voxygen/src/anim/src/quadruped_low/mod.rs b/voxygen/src/anim/src/quadruped_low/mod.rs index d36eba621b..c359150001 100644 --- a/voxygen/src/anim/src/quadruped_low/mod.rs +++ b/voxygen/src/anim/src/quadruped_low/mod.rs @@ -8,10 +8,12 @@ pub use self::{ alpha::AlphaAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, }; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::quadruped_low::Body; + skeleton_impls!(struct QuadrupedLowSkeleton { + head_upper, + head_lower, @@ -27,6 +29,7 @@ skeleton_impls!(struct QuadrupedLowSkeleton { impl Skeleton for QuadrupedLowSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 10; #[cfg(feature = "use-dyn-lib")] @@ -102,8 +105,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::quadruped_low::Body> for SkeletonAttr { - fn from(body: &'a comp::quadruped_low::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::quadruped_low::Species::*; Self { head_upper: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/quadruped_medium/mod.rs b/voxygen/src/anim/src/quadruped_medium/mod.rs index 08e5db484b..78311579d3 100644 --- a/voxygen/src/anim/src/quadruped_medium/mod.rs +++ b/voxygen/src/anim/src/quadruped_medium/mod.rs @@ -8,10 +8,12 @@ pub use self::{ alpha::AlphaAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, }; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::quadruped_medium::Body; + skeleton_impls!(struct QuadrupedMediumSkeleton { + head_upper, + head_lower, @@ -32,6 +34,7 @@ skeleton_impls!(struct QuadrupedMediumSkeleton { impl Skeleton for QuadrupedMediumSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 15; #[cfg(feature = "use-dyn-lib")] @@ -124,8 +127,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::quadruped_medium::Body> for SkeletonAttr { - fn from(body: &'a comp::quadruped_medium::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::quadruped_medium::Species::*; Self { head_upper: match (body.species, body.body_type) { diff --git a/voxygen/src/anim/src/quadruped_small/mod.rs b/voxygen/src/anim/src/quadruped_small/mod.rs index 05142e0639..5d5de9e931 100644 --- a/voxygen/src/anim/src/quadruped_small/mod.rs +++ b/voxygen/src/anim/src/quadruped_small/mod.rs @@ -6,10 +6,12 @@ pub mod run; // Reexports pub use self::{feed::FeedAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; -use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; +use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +pub type Body = comp::quadruped_small::Body; + skeleton_impls!(struct QuadrupedSmallSkeleton { + head, + chest, @@ -22,6 +24,7 @@ skeleton_impls!(struct QuadrupedSmallSkeleton { impl Skeleton for QuadrupedSmallSkeleton { type Attr = SkeletonAttr; + type Body = Body; const BONE_COUNT: usize = 7; #[cfg(feature = "use-dyn-lib")] @@ -90,8 +93,8 @@ impl Default for SkeletonAttr { } } -impl<'a> From<&'a comp::quadruped_small::Body> for SkeletonAttr { - fn from(body: &'a comp::quadruped_small::Body) -> Self { +impl<'a> From<&'a Body> for SkeletonAttr { + fn from(body: &'a Body) -> Self { use comp::quadruped_small::Species::*; Self { head: match (body.species, body.body_type) { diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index cd177dae6c..eb381ae404 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -1,8 +1,11 @@ use super::*; use crate::audio::sfx::SfxEvent; use common::{ - assets, - comp::{item::tool::ToolCategory, CharacterAbilityType, CharacterState, ItemConfig, Loadout}, + assets::Asset, + comp::{ + item::{tool::ToolCategory, ItemAsset}, + CharacterAbilityType, CharacterState, ItemConfig, Loadout, + }, states, }; use std::time::{Duration, Instant}; @@ -12,7 +15,7 @@ fn maps_wield_while_equipping() { let mut loadout = Loadout::default(); loadout.active_item = Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.axe.starter_axe"), + item: ItemAsset::load_expect_cloned("common.items.weapons.axe.starter_axe"), ability1: None, ability2: None, ability3: None, @@ -40,7 +43,7 @@ fn maps_unwield() { let mut loadout = Loadout::default(); loadout.active_item = Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.bow.starter_bow"), + item: ItemAsset::load_expect_cloned("common.items.weapons.bow.starter_bow"), ability1: None, ability2: None, ability3: None, @@ -66,7 +69,7 @@ fn maps_basic_melee() { let mut loadout = Loadout::default(); loadout.active_item = Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.axe.starter_axe"), + item: ItemAsset::load_expect_cloned("common.items.weapons.axe.starter_axe"), ability1: None, ability2: None, ability3: None, @@ -102,7 +105,7 @@ fn matches_ability_stage() { let mut loadout = Loadout::default(); loadout.active_item = Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.sword.starter_sword"), + item: ItemAsset::load_expect_cloned("common.items.weapons.sword.starter_sword"), ability1: None, ability2: None, ability3: None, @@ -143,7 +146,7 @@ fn ignores_different_ability_stage() { let mut loadout = Loadout::default(); loadout.active_item = Some(ItemConfig { - item: assets::load_expect_cloned("common.items.weapons.sword.starter_sword"), + item: ItemAsset::load_expect_cloned("common.items.weapons.sword.starter_sword"), ability1: None, ability2: None, ability3: None, diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index cd98cee9eb..155fd18bc0 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -97,7 +97,7 @@ impl ItemImgs { pub fn new(ui: &mut Ui, not_found: Id) -> Self { let mut indicator = ReloadIndicator::new(); Self { - map: assets::load_watched::( + map: ItemImagesSpec::load_watched( "voxygen.item_image_manifest", &mut indicator, ) @@ -118,7 +118,7 @@ impl ItemImgs { /// Reuses img ids pub fn reload_if_changed(&mut self, ui: &mut Ui) { if self.indicator.reloaded() { - for (kind, spec) in assets::load::("voxygen.item_image_manifest") + for (kind, spec) in ItemImagesSpec::load("voxygen.item_image_manifest") .expect("Unable to load item image manifest") .0 .iter() @@ -160,21 +160,21 @@ impl ItemImgs { // TODO: remove code dup? fn graceful_load_vox(specifier: &str) -> Arc { let full_specifier: String = ["voxygen.", specifier].concat(); - match assets::load::(full_specifier.as_str()) { + match DotVoxData::load(full_specifier.as_str()) { Ok(dot_vox) => dot_vox, Err(_) => { error!(?full_specifier, "Could not load vox file for item images",); - assets::load_expect::("voxygen.voxel.not_found") + DotVoxData::load_expect("voxygen.voxel.not_found") }, } } fn graceful_load_img(specifier: &str) -> Arc { let full_specifier: String = ["voxygen.", specifier].concat(); - match assets::load::(full_specifier.as_str()) { + match DynamicImage::load(full_specifier.as_str()) { Ok(img) => img, Err(_) => { error!(?full_specifier, "Could not load image file for item images"); - assets::load_expect::("voxygen.element.not_found") + DynamicImage::load_expect("voxygen.element.not_found") }, } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 0950b188c3..2e4a298c0f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -56,7 +56,7 @@ use crate::{ GlobalState, }; use client::Client; -use common::{assets::load_expect, comp, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol}; +use common::{assets::Asset, comp, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol}; use conrod_core::{ text::cursor::Index, widget::{self, Button, Image, Text}, @@ -602,7 +602,7 @@ impl Hud { // Load item images. let item_imgs = ItemImgs::new(&mut ui, imgs.not_found); // Load language. - let voxygen_i18n = load_expect::(&i18n_asset_key( + let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); // Load fonts. diff --git a/voxygen/src/i18n.rs b/voxygen/src/i18n.rs index 2558adaaf2..1de029c950 100644 --- a/voxygen/src/i18n.rs +++ b/voxygen/src/i18n.rs @@ -1,7 +1,4 @@ -use common::{ - assets, - assets::{load_expect, load_glob, Asset}, -}; +use common::assets::{self, Asset}; use deunicode::deunicode; use ron::de::from_reader; use serde_derive::*; @@ -100,7 +97,7 @@ impl VoxygenLocalization { /// Return the missing keys compared to the reference language pub fn list_missing_entries(&self) -> (HashSet, HashSet) { let reference_localization = - load_expect::(i18n_asset_key(REFERENCE_LANG).as_ref()); + VoxygenLocalization::load_expect(i18n_asset_key(REFERENCE_LANG).as_ref()); let reference_string_keys: HashSet<_> = reference_localization.string_map.keys().cloned().collect(); @@ -169,7 +166,7 @@ impl Asset for VoxygenLocalization { /// Load all the available languages located in the Voxygen asset directory pub fn list_localizations() -> Vec { let voxygen_locales_assets = "voxygen.i18n.*"; - let lang_list = load_glob::(voxygen_locales_assets).unwrap(); + let lang_list = VoxygenLocalization::load_glob(voxygen_locales_assets).unwrap(); lang_list.iter().map(|e| (*e).metadata.clone()).collect() } diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index d119fdb788..f66beb9819 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -15,7 +15,7 @@ use veloren_voxygen::{ }; use common::{ - assets::{load_watched, watch}, + assets::{watch, Asset}, clock::Clock, }; use std::panic; @@ -132,7 +132,7 @@ fn main() { let profile = Profile::load(); let mut localization_watcher = watch::ReloadIndicator::new(); - let localized_strings = load_watched::( + let localized_strings = VoxygenLocalization::load_watched( &i18n_asset_key(&settings.language.selected_language), &mut localization_watcher, ) @@ -144,7 +144,7 @@ fn main() { "Impossible to load language: change to the default language (English) instead.", ); settings.language.selected_language = i18n::REFERENCE_LANG.to_owned(); - load_watched::( + VoxygenLocalization::load_watched( &i18n_asset_key(&settings.language.selected_language), &mut localization_watcher, ) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 2edbc0f330..e405f78b8d 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -10,7 +10,7 @@ use crate::{ Direction, GlobalState, PlayState, PlayStateResult, }; use client::{self, Client}; -use common::{assets, comp, msg::ClientState, state::DeltaTime}; +use common::{assets::Asset, comp, msg::ClientState, state::DeltaTime}; use specs::WorldExt; use std::{cell::RefCell, rc::Rc}; use tracing::error; @@ -126,6 +126,7 @@ impl PlayState for CharSelectionState { time: client.state().get_time(), delta_time: client.state().ecs().read_resource::().0, tick: client.get_tick(), + thread_pool: client.thread_pool(), body: humanoid_body, gamma: global_state.settings.graphics.gamma, mouse_smoothing: global_state.settings.gameplay.smooth_pan_enable, @@ -143,7 +144,7 @@ impl PlayState for CharSelectionState { } // Tick the client (currently only to keep the connection alive). - let localized_strings = assets::load_expect::(&i18n_asset_key( + let localized_strings = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index a3fd267cc1..d45afc32f9 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -11,10 +11,9 @@ use crate::{ }; use client::Client; use common::{ - assets, - assets::load_expect, + assets::Asset, character::{Character, CharacterItem, MAX_CHARACTERS_PER_PLAYER}, - comp::{self, humanoid}, + comp::{self, humanoid, item::ItemAsset}, LoadoutBuilder, }; use conrod_core::{ @@ -321,7 +320,7 @@ impl CharSelectionUi { let imgs = Imgs::load(&mut ui).expect("Failed to load images!"); let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!"); // Load language - let voxygen_i18n = load_expect::(&i18n_asset_key( + let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); // Load fonts. @@ -378,20 +377,24 @@ impl CharSelectionUi { }, Mode::Create { loadout, tool, .. } => { loadout.active_item = tool.map(|tool| comp::ItemConfig { - item: (*load_expect::(tool)).clone(), + // FIXME: Error gracefully. + item: (*ItemAsset::load_expect(tool)).clone(), ability1: None, ability2: None, ability3: None, block_ability: None, dodge_ability: None, }); - loadout.chest = Some(assets::load_expect_cloned( + // FIXME: Error gracefully. + loadout.chest = Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.rugged_chest", )); - loadout.pants = Some(assets::load_expect_cloned( + // FIXME: Error gracefully. + loadout.pants = Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.rugged_pants", )); - loadout.foot = Some(assets::load_expect_cloned( + // FIXME: Error gracefully. + loadout.foot = Some(ItemAsset::load_expect_cloned( "common.items.armor.starter.sandals_0", )); Some(loadout.clone()) diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index 2366e82e45..bbc11c846e 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -9,7 +9,7 @@ use crate::{ PlayStateResult, }; use client_init::{ClientInit, Error as InitError, Msg as InitMsg}; -use common::{assets::load_expect, comp}; +use common::{assets::Asset, comp}; use tracing::{error, warn}; use ui::{Event as MainMenuEvent, MainMenuUi}; @@ -46,7 +46,7 @@ impl PlayState for MainMenuState { } fn tick(&mut self, global_state: &mut GlobalState, events: Vec) -> PlayStateResult { - let localized_strings = load_expect::( + let localized_strings = crate::i18n::VoxygenLocalization::load_expect( &crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language), ); diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index dc89969460..a4de9e9c51 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -9,7 +9,7 @@ use crate::{ }, GlobalState, }; -use common::assets::load_expect; +use common::assets::Asset; use conrod_core::{ color, color::TRANSPARENT, @@ -17,6 +17,7 @@ use conrod_core::{ widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; +use image::DynamicImage; use rand::{seq::SliceRandom, thread_rng, Rng}; use std::time::Duration; @@ -205,12 +206,12 @@ impl<'a> MainMenuUi { let imgs = Imgs::load(&mut ui).expect("Failed to load images"); let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!"); let bg_img_id = ui.add_graphic(Graphic::Image( - load_expect(bg_imgs.choose(&mut rng).unwrap()), + DynamicImage::load_expect(bg_imgs.choose(&mut rng).unwrap()), None, )); //let chosen_tip = *tips.choose(&mut rng).unwrap(); // Load language - let voxygen_i18n = load_expect::(&i18n_asset_key( + let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); // Load fonts. diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index b89997da99..b37a86bd23 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -12,7 +12,7 @@ use super::{ AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, ShadowMapMode, ShadowMode, WrapMode, }; -use common::assets::{self, watch::ReloadIndicator}; +use common::assets::{self, watch::ReloadIndicator, Asset}; use core::convert::TryFrom; use gfx::{ self, @@ -21,6 +21,11 @@ use gfx::{ traits::{Device, Factory, FactoryExt}, }; use glsl_include::Context as IncludeContext; +use image::DynamicImage; +use std::{ + fs::File, + io::{BufReader, Read}, +}; use tracing::{error, warn}; use vek::*; @@ -87,6 +92,21 @@ pub type ColLightInfo = ( Vec2, ); +/// Load from a GLSL file. +pub struct Glsl; + +impl Asset for Glsl { + type Output = String; + + const ENDINGS: &'static [&'static str] = &["glsl"]; + + fn parse(mut buf_reader: BufReader) -> Result { + let mut string = String::new(); + buf_reader.read_to_string(&mut string)?; + Ok(string) + } +} + /// A type that holds shadow map data. Since shadow mapping may not be /// supported on all platforms, we try to keep it separate. pub struct ShadowMapRenderer { @@ -240,7 +260,7 @@ impl Renderer { let noise_tex = Texture::new( &mut factory, - &assets::load_expect("voxygen.texture.noise"), + &DynamicImage::load_expect("voxygen.texture.noise"), Some(gfx::texture::FilterMethod::Bilinear), Some(gfx::texture::WrapMode::Tile), None, @@ -1654,32 +1674,19 @@ fn create_pipelines( ), RenderError, > { - let constants = assets::load_watched::( - "voxygen.shaders.include.constants", - shader_reload_indicator, - ) - .unwrap(); + let constants = + Glsl::load_watched("voxygen.shaders.include.constants", shader_reload_indicator).unwrap(); let globals = - assets::load_watched::("voxygen.shaders.include.globals", shader_reload_indicator) - .unwrap(); - let sky = - assets::load_watched::("voxygen.shaders.include.sky", shader_reload_indicator) - .unwrap(); + Glsl::load_watched("voxygen.shaders.include.globals", shader_reload_indicator).unwrap(); + let sky = Glsl::load_watched("voxygen.shaders.include.sky", shader_reload_indicator).unwrap(); let light = - assets::load_watched::("voxygen.shaders.include.light", shader_reload_indicator) - .unwrap(); - let srgb = - assets::load_watched::("voxygen.shaders.include.srgb", shader_reload_indicator) - .unwrap(); + Glsl::load_watched("voxygen.shaders.include.light", shader_reload_indicator).unwrap(); + let srgb = Glsl::load_watched("voxygen.shaders.include.srgb", shader_reload_indicator).unwrap(); let random = - assets::load_watched::("voxygen.shaders.include.random", shader_reload_indicator) - .unwrap(); - let lod = - assets::load_watched::("voxygen.shaders.include.lod", shader_reload_indicator) - .unwrap(); + Glsl::load_watched("voxygen.shaders.include.random", shader_reload_indicator).unwrap(); + let lod = Glsl::load_watched("voxygen.shaders.include.lod", shader_reload_indicator).unwrap(); let shadows = - assets::load_watched::("voxygen.shaders.include.shadows", shader_reload_indicator) - .unwrap(); + Glsl::load_watched("voxygen.shaders.include.shadows", shader_reload_indicator).unwrap(); // We dynamically add extra configuration settings to the constants file. let constants = format!( @@ -1716,7 +1723,7 @@ fn create_pipelines( }, ); - let anti_alias = assets::load_watched::( + let anti_alias = Glsl::load_watched( &["voxygen.shaders.antialias.", match mode.aa { AaMode::None | AaMode::SsaaX4 => "none", AaMode::Fxaa => "fxaa", @@ -1729,7 +1736,7 @@ fn create_pipelines( ) .unwrap(); - let cloud = assets::load_watched::( + let cloud = Glsl::load_watched( &["voxygen.shaders.include.cloud.", match mode.cloud { CloudMode::None => "none", CloudMode::Regular => "regular", @@ -1752,28 +1759,27 @@ fn create_pipelines( include_ctx.include("cloud.glsl", &cloud); let figure_vert = - assets::load_watched::("voxygen.shaders.figure-vert", shader_reload_indicator) - .unwrap(); + Glsl::load_watched("voxygen.shaders.figure-vert", shader_reload_indicator).unwrap(); - let terrain_point_shadow_vert = assets::load_watched::( + let terrain_point_shadow_vert = Glsl::load_watched( "voxygen.shaders.light-shadows-vert", shader_reload_indicator, ) .unwrap(); - let terrain_directed_shadow_vert = assets::load_watched::( + let terrain_directed_shadow_vert = Glsl::load_watched( "voxygen.shaders.light-shadows-directed-vert", shader_reload_indicator, ) .unwrap(); - let figure_directed_shadow_vert = assets::load_watched::( + let figure_directed_shadow_vert = Glsl::load_watched( "voxygen.shaders.light-shadows-figure-vert", shader_reload_indicator, ) .unwrap(); - let directed_shadow_frag = &assets::load_watched::( + let directed_shadow_frag = Glsl::load_watched( "voxygen.shaders.light-shadows-directed-frag", shader_reload_indicator, ) @@ -1783,10 +1789,8 @@ fn create_pipelines( let skybox_pipeline = create_pipeline( factory, skybox::pipe::new(), - &assets::load_watched::("voxygen.shaders.skybox-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::("voxygen.shaders.skybox-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.skybox-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.skybox-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1796,8 +1800,7 @@ fn create_pipelines( factory, figure::pipe::new(), &figure_vert, - &assets::load_watched::("voxygen.shaders.figure-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.figure-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1806,10 +1809,8 @@ fn create_pipelines( let terrain_pipeline = create_pipeline( factory, terrain::pipe::new(), - &assets::load_watched::("voxygen.shaders.terrain-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::("voxygen.shaders.terrain-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.terrain-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.terrain-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1818,9 +1819,8 @@ fn create_pipelines( let fluid_pipeline = create_pipeline( factory, fluid::pipe::new(), - &assets::load_watched::("voxygen.shaders.fluid-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::( + &Glsl::load_watched("voxygen.shaders.fluid-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched( &["voxygen.shaders.fluid-frag.", match mode.fluid { FluidMode::Cheap => "cheap", FluidMode::Shiny => "shiny", @@ -1837,10 +1837,8 @@ fn create_pipelines( let sprite_pipeline = create_pipeline( factory, sprite::pipe::new(), - &assets::load_watched::("voxygen.shaders.sprite-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::("voxygen.shaders.sprite-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.sprite-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.sprite-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1849,10 +1847,8 @@ fn create_pipelines( let particle_pipeline = create_pipeline( factory, particle::pipe::new(), - &assets::load_watched::("voxygen.shaders.particle-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::("voxygen.shaders.particle-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.particle-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.particle-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1861,10 +1857,8 @@ fn create_pipelines( let ui_pipeline = create_pipeline( factory, ui::pipe::new(), - &assets::load_watched::("voxygen.shaders.ui-vert", shader_reload_indicator) - .unwrap(), - &assets::load_watched::("voxygen.shaders.ui-frag", shader_reload_indicator) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.ui-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.ui-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1873,16 +1867,8 @@ fn create_pipelines( let lod_terrain_pipeline = create_pipeline( factory, lod_terrain::pipe::new(), - &assets::load_watched::( - "voxygen.shaders.lod-terrain-vert", - shader_reload_indicator, - ) - .unwrap(), - &assets::load_watched::( - "voxygen.shaders.lod-terrain-frag", - shader_reload_indicator, - ) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.lod-terrain-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.lod-terrain-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1891,16 +1877,8 @@ fn create_pipelines( let postprocess_pipeline = create_pipeline( factory, postprocess::pipe::new(), - &assets::load_watched::( - "voxygen.shaders.postprocess-vert", - shader_reload_indicator, - ) - .unwrap(), - &assets::load_watched::( - "voxygen.shaders.postprocess-frag", - shader_reload_indicator, - ) - .unwrap(), + &Glsl::load_watched("voxygen.shaders.postprocess-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.postprocess-frag", shader_reload_indicator).unwrap(), &include_ctx, gfx::state::CullFace::Back, )?; @@ -1918,7 +1896,7 @@ fn create_pipelines( ..figure::pipe::new() }, &figure_vert, - &assets::load_watched::( + &Glsl::load_watched( "voxygen.shaders.player-shadow-frag", shader_reload_indicator, ) @@ -1933,13 +1911,13 @@ fn create_pipelines( shadow::pipe::new(), &terrain_point_shadow_vert, Some( - &assets::load_watched::( + &Glsl::load_watched( "voxygen.shaders.light-shadows-geom", shader_reload_indicator, ) .unwrap(), ), - &assets::load_watched::( + &Glsl::load_watched( "voxygen.shaders.light-shadows-frag", shader_reload_indicator, ) diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index ce4411bb6e..b7dca468d9 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -1,7 +1,9 @@ -use super::{load::*, FigureModelEntry}; +use super::{load::BodySpec, FigureModelEntry}; use crate::{ mesh::{greedy::GreedyMesh, Meshable}, - render::{BoneMeshes, FigureModel, FigurePipeline, Mesh, Renderer, TerrainPipeline}, + render::{ + BoneMeshes, ColLightInfo, FigureModel, FigurePipeline, Mesh, Renderer, TerrainPipeline, + }, scene::camera::CameraMode, }; use anim::Skeleton; @@ -13,41 +15,72 @@ use common::{ tool::ToolKind, ItemKind, }, - Body, CharacterState, Loadout, + CharacterState, Loadout, }, figure::Segment, vol::BaseVol, }; -use core::convert::TryInto; +use core::{hash::Hash, ops::Range}; +use crossbeam::atomic; use hashbrown::{hash_map::Entry, HashMap}; +use std::sync::Arc; use vek::*; -pub type FigureModelEntryLod = FigureModelEntry<3>; +/// A type produced by mesh worker threads corresponding to the information +/// needed to mesh figures. +struct MeshWorkerResponse { + col_light: ColLightInfo, + opaque: Mesh, + bounds: anim::vek::Aabb, + vertex_range: [Range; N], +} -#[derive(Eq, Hash, PartialEq)] -struct FigureKey { +/// NOTE: To test this cell for validity, we currently first use +/// Arc::get_mut(), and then only if that succeeds do we call AtomicCell::take. +/// This way, we avoid all atomic updates for the fast path read in the "not yet +/// updated" case (though it would be faster without weak pointers); since once +/// it's updated, we switch from `Pending` to `Done`, this is only suboptimal +/// for one frame. +type MeshWorkerCell = atomic::AtomicCell>>; + +/// A future FigureModelEntryLod. +enum FigureModelEntryFuture { + /// We can poll the future to see whether the figure model is ready. + // TODO: See if we can find away to either get rid of this Arc, or reuse Arcs across different + // figures. Updates to uvth for thread pool shared storage might obviate this requirement. + Pending(Arc>), + /// Stores the already-meshed model. + Done(FigureModelEntry), +} + +const LOD_COUNT: usize = 3; + +type FigureModelEntryLod<'b> = Option<&'b FigureModelEntry>; + +#[derive(Clone, Eq, Hash, PartialEq)] +pub struct FigureKey { /// Body pointed to by this key. - body: Body, + pub(super) body: Body, /// Extra state. - extra: Option>, + pub(super) extra: Option>, } /// Character data that should be visible when tools are visible (i.e. in third /// person or when the character is in a tool-using state). #[derive(Eq, Hash, PartialEq)] -pub struct CharacterToolKey { - active: Option, - second: Option, +pub(super) struct CharacterToolKey { + pub active: Option, + pub second: Option, } /// Character data that exists in third person only. #[derive(Eq, Hash, PartialEq)] -struct CharacterThirdPersonKey { - shoulder: Option, - chest: Option, - belt: Option, - back: Option, - pants: Option, +pub(super) struct CharacterThirdPersonKey { + pub shoulder: Option, + pub chest: Option, + pub belt: Option, + pub back: Option, + pub pants: Option, } #[derive(Eq, Hash, PartialEq)] @@ -55,9 +88,9 @@ struct CharacterThirdPersonKey { /// store only the minimum information required to correctly update the model. /// /// TODO: Memoize, etc. -struct CharacterCacheKey { +pub(super) struct CharacterCacheKey { /// Character state that is only visible in third person. - third_person: Option, + pub third_person: Option, /// Tool state should be present when a character is either in third person, /// or is in first person and the character state is tool-using. /// @@ -66,10 +99,10 @@ struct CharacterCacheKey { /// tools are equipped, but currently we are more focused on the big /// performance impact of recreating the whole model whenever the character /// state changes, so for now we don't bother with this. - tool: Option, - lantern: Option, - hand: Option, - foot: Option, + pub tool: Option, + pub lantern: Option, + pub hand: Option, + pub foot: Option, } impl CharacterCacheKey { @@ -197,813 +230,53 @@ impl CharacterCacheKey { pub struct FigureModelCache where Skel: Skeleton, + Skel::Body: BodySpec, { - models: HashMap, + models: HashMap, ((FigureModelEntryFuture, Skel::Attr), u64)>, + manifests: Arc<::Spec>, manifest_indicator: ReloadIndicator, } -impl FigureModelCache { +impl FigureModelCache +where + Skel::Body: BodySpec + Eq + Hash, +{ #[allow(clippy::new_without_default)] // TODO: Pending review in #587 pub fn new() -> Self { + let mut manifest_indicator = ReloadIndicator::new(); Self { models: HashMap::new(), - manifest_indicator: ReloadIndicator::new(), + // NOTE: It might be better to bubble this error up rather than panicking. + manifests: Arc::new( + ::load_watched(&mut manifest_indicator) + .expect("Could not load manifests for body type"), + ), + manifest_indicator, } } - /// NOTE: We deliberately call this function with only the key into the - /// cache, to enforce that the cached state only depends on the key. We - /// may end up using a mechanism different from this cache eventually, - /// in which case this strategy might change. - fn bone_meshes( - FigureKey { body, extra }: &FigureKey, - manifest_indicator: &mut ReloadIndicator, - mut generate_mesh: impl FnMut(Segment, Vec3) -> BoneMeshes, - ) -> [Option; 16] { - match body { - Body::Humanoid(body) => { - let humanoid_color_spec = HumColorSpec::load_watched(manifest_indicator); - let humanoid_head_spec = HumHeadSpec::load_watched(manifest_indicator); - let humanoid_armor_shoulder_spec = - HumArmorShoulderSpec::load_watched(manifest_indicator); - let humanoid_armor_chest_spec = HumArmorChestSpec::load_watched(manifest_indicator); - let humanoid_armor_hand_spec = HumArmorHandSpec::load_watched(manifest_indicator); - let humanoid_armor_belt_spec = HumArmorBeltSpec::load_watched(manifest_indicator); - let humanoid_armor_back_spec = HumArmorBackSpec::load_watched(manifest_indicator); - let humanoid_armor_lantern_spec = - HumArmorLanternSpec::load_watched(manifest_indicator); - let humanoid_armor_pants_spec = HumArmorPantsSpec::load_watched(manifest_indicator); - let humanoid_armor_foot_spec = HumArmorFootSpec::load_watched(manifest_indicator); - let humanoid_main_weapon_spec = HumMainWeaponSpec::load_watched(manifest_indicator); - - const DEFAULT_LOADOUT: CharacterCacheKey = CharacterCacheKey { - third_person: None, - tool: None, - lantern: None, - hand: None, - foot: None, - }; - - // TODO: This is bad code, maybe this method should return Option<_> - let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT); - let third_person = loadout.third_person.as_ref(); - let tool = loadout.tool.as_ref(); - let lantern = loadout.lantern.as_deref(); - let hand = loadout.hand.as_deref(); - let foot = loadout.foot.as_deref(); - - [ - third_person.map(|_| { - humanoid_head_spec.mesh_head( - body, - &humanoid_color_spec, - |segment, offset| generate_mesh(segment, offset), - ) - }), - third_person.map(|loadout| { - humanoid_armor_chest_spec.mesh_chest( - body, - &humanoid_color_spec, - loadout.chest.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - third_person.map(|loadout| { - humanoid_armor_belt_spec.mesh_belt( - body, - &humanoid_color_spec, - loadout.belt.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - third_person.map(|loadout| { - humanoid_armor_back_spec.mesh_back( - body, - &humanoid_color_spec, - loadout.back.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - third_person.map(|loadout| { - humanoid_armor_pants_spec.mesh_pants( - body, - &humanoid_color_spec, - loadout.pants.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - Some(humanoid_armor_hand_spec.mesh_left_hand( - body, - &humanoid_color_spec, - hand, - |segment, offset| generate_mesh(segment, offset), - )), - Some(humanoid_armor_hand_spec.mesh_right_hand( - body, - &humanoid_color_spec, - hand, - |segment, offset| generate_mesh(segment, offset), - )), - Some(humanoid_armor_foot_spec.mesh_left_foot( - body, - &humanoid_color_spec, - foot, - |segment, offset| generate_mesh(segment, offset), - )), - Some(humanoid_armor_foot_spec.mesh_right_foot( - body, - &humanoid_color_spec, - foot, - |segment, offset| generate_mesh(segment, offset), - )), - third_person.map(|loadout| { - humanoid_armor_shoulder_spec.mesh_left_shoulder( - body, - &humanoid_color_spec, - loadout.shoulder.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - third_person.map(|loadout| { - humanoid_armor_shoulder_spec.mesh_right_shoulder( - body, - &humanoid_color_spec, - loadout.shoulder.as_deref(), - |segment, offset| generate_mesh(segment, offset), - ) - }), - Some(mesh_glider(|segment, offset| { - generate_mesh(segment, offset) - })), - tool.map(|tool| { - humanoid_main_weapon_spec.mesh_main_weapon( - tool.active.as_ref(), - false, - |segment, offset| generate_mesh(segment, offset), - ) - }), - tool.map(|tool| { - humanoid_main_weapon_spec.mesh_main_weapon( - tool.second.as_ref(), - true, - |segment, offset| generate_mesh(segment, offset), - ) - }), - Some(humanoid_armor_lantern_spec.mesh_lantern( - body, - &humanoid_color_spec, - lantern, - |segment, offset| generate_mesh(segment, offset), - )), - Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))), - ] - }, - Body::QuadrupedSmall(body) => { - let quadruped_small_central_spec = - QuadrupedSmallCentralSpec::load_watched(manifest_indicator); - let quadruped_small_lateral_spec = - QuadrupedSmallLateralSpec::load_watched(manifest_indicator); - - [ - Some(quadruped_small_central_spec.mesh_head( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_central_spec.mesh_chest( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_lateral_spec.mesh_foot_fl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_lateral_spec.mesh_foot_fr( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_lateral_spec.mesh_foot_bl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_lateral_spec.mesh_foot_br( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_small_central_spec.mesh_tail( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::QuadrupedMedium(body) => { - let quadruped_medium_central_spec = - QuadrupedMediumCentralSpec::load_watched(manifest_indicator); - let quadruped_medium_lateral_spec = - QuadrupedMediumLateralSpec::load_watched(manifest_indicator); - - [ - Some(quadruped_medium_central_spec.mesh_head_upper( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_head_lower( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_jaw( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_tail( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_torso_front( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_torso_back( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_central_spec.mesh_ears( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_leg_fl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_leg_fr( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_leg_bl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_leg_br( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_foot_fl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_foot_fr( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_foot_bl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_medium_lateral_spec.mesh_foot_br( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - ] - }, - Body::BirdMedium(body) => { - let bird_medium_center_spec = - BirdMediumCenterSpec::load_watched(manifest_indicator); - let bird_medium_lateral_spec = - BirdMediumLateralSpec::load_watched(manifest_indicator); - - [ - Some(bird_medium_center_spec.mesh_head( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_center_spec.mesh_torso( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_center_spec.mesh_tail( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_lateral_spec.mesh_wing_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_lateral_spec.mesh_wing_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_lateral_spec.mesh_foot_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(bird_medium_lateral_spec.mesh_foot_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::FishMedium(body) => [ - Some(mesh_fish_medium_head(body.head, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_medium_torso(body.torso, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_medium_rear(body.rear, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_medium_tail(body.tail, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_medium_fin_l(body.fin_l, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_medium_fin_r(body.fin_r, |segment, offset| { - generate_mesh(segment, offset) - })), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::Dragon(body) => { - let dragon_center_spec = DragonCenterSpec::load_watched(manifest_indicator); - let dragon_lateral_spec = DragonLateralSpec::load_watched(manifest_indicator); - - [ - Some(dragon_center_spec.mesh_head_upper( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_head_lower( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_jaw( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_chest_front( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_chest_rear( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_tail_front( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_center_spec.mesh_tail_rear( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_wing_in_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_wing_in_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_wing_out_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_wing_out_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_foot_fl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_foot_fr( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_foot_bl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(dragon_lateral_spec.mesh_foot_br( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - ] - }, - Body::BirdSmall(body) => [ - Some(mesh_bird_small_head(body.head, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_bird_small_torso(body.torso, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_bird_small_wing_l(body.wing_l, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_bird_small_wing_r(body.wing_r, |segment, offset| { - generate_mesh(segment, offset) - })), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::FishSmall(body) => [ - Some(mesh_fish_small_torso(body.torso, |segment, offset| { - generate_mesh(segment, offset) - })), - Some(mesh_fish_small_tail(body.tail, |segment, offset| { - generate_mesh(segment, offset) - })), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - Body::BipedLarge(body) => { - let biped_large_center_spec = - BipedLargeCenterSpec::load_watched(manifest_indicator); - let biped_large_lateral_spec = - BipedLargeLateralSpec::load_watched(manifest_indicator); - - [ - Some(biped_large_center_spec.mesh_head( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_jaw( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_torso_upper( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_torso_lower( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_tail( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_main( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_center_spec.mesh_second( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_shoulder_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_shoulder_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_hand_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_hand_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_leg_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_leg_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_foot_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(biped_large_lateral_spec.mesh_foot_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - ] - }, - Body::Golem(body) => { - let golem_center_spec = GolemCenterSpec::load_watched(manifest_indicator); - let golem_lateral_spec = GolemLateralSpec::load_watched(manifest_indicator); - - [ - Some(golem_center_spec.mesh_head( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_center_spec.mesh_torso_upper( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_shoulder_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_shoulder_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_hand_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_hand_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_leg_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_leg_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_foot_l( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(golem_lateral_spec.mesh_foot_r( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - None, - None, - None, - None, - None, - ] - }, - Body::Critter(body) => { - let critter_center_spec = CritterCenterSpec::load_watched(manifest_indicator); - - [ - Some(critter_center_spec.mesh_head( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(critter_center_spec.mesh_chest( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(critter_center_spec.mesh_feet_f( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(critter_center_spec.mesh_feet_b( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(critter_center_spec.mesh_tail( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ] - }, - Body::QuadrupedLow(body) => { - let quadruped_low_central_spec = - QuadrupedLowCentralSpec::load_watched(manifest_indicator); - let quadruped_low_lateral_spec = - QuadrupedLowLateralSpec::load_watched(manifest_indicator); - - [ - Some(quadruped_low_central_spec.mesh_head_upper( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_central_spec.mesh_head_lower( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_central_spec.mesh_jaw( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_central_spec.mesh_chest( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_central_spec.mesh_tail_front( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_central_spec.mesh_tail_rear( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_lateral_spec.mesh_foot_fl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_lateral_spec.mesh_foot_fr( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_lateral_spec.mesh_foot_bl( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - Some(quadruped_low_lateral_spec.mesh_foot_br( - body.species, - body.body_type, - |segment, offset| generate_mesh(segment, offset), - )), - None, - None, - None, - None, - None, - None, - ] - }, - Body::Object(object) => [ - Some(mesh_object(object, generate_mesh)), - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - ], - } - } - - pub fn get_or_create_model( - &mut self, - renderer: &mut Renderer, - col_lights: &mut super::FigureColLights, - body: Body, + /// NOTE: Intended for render time (useful with systems like wgpu that + /// expect data used by the rendering pipelines to be stable throughout + /// the render pass). + /// + /// NOTE: Since this is intended to be called primarily in order to render + /// the model, we don't return skeleton data. + pub fn get_model<'b>( + &'b self, + // TODO: If we ever convert to using an atlas here, use this. + _col_lights: &super::FigureColLights, + body: Skel::Body, loadout: Option<&Loadout>, - tick: u64, + // TODO: Consider updating the tick by putting it in a Cell. + _tick: u64, camera_mode: CameraMode, character_state: Option<&CharacterState>, - ) -> &(FigureModelEntryLod, Skel::Attr) - where - for<'a> &'a common::comp::Body: std::convert::TryInto, - Skel::Attr: Default, - { + ) -> FigureModelEntryLod<'b> { + // TODO: Use raw entries to avoid lots of allocation (among other things). let key = FigureKey { body, extra: loadout.map(|loadout| { - Box::new(CharacterCacheKey::from( + Arc::new(CharacterCacheKey::from( character_state, camera_mode, loadout, @@ -1011,21 +284,90 @@ impl FigureModelCache { }), }; + if let Some(((FigureModelEntryFuture::Done(model), _), _)) = self.models.get(&key) { + Some(model) + } else { + None + } + } + + pub fn get_or_create_model<'c>( + &'c mut self, + renderer: &mut Renderer, + col_lights: &mut super::FigureColLights, + body: Skel::Body, + loadout: Option<&Loadout>, + tick: u64, + camera_mode: CameraMode, + character_state: Option<&CharacterState>, + thread_pool: &uvth::ThreadPool, + ) -> (FigureModelEntryLod<'c>, &'c Skel::Attr) + where + for<'a> &'a Skel::Body: Into, + Skel::Body: Clone + Send + Sync + 'static, + ::Spec: Send + Sync + 'static, + { + let skeleton_attr = (&body).into(); + let key = FigureKey { + body, + extra: loadout.map(|loadout| { + Arc::new(CharacterCacheKey::from( + character_state, + camera_mode, + loadout, + )) + }), + }; + + // TODO: Use raw entries to avoid significant performance overhead. match self.models.entry(key) { Entry::Occupied(o) => { - let (model, last_used) = o.into_mut(); + let ((model, skel), last_used) = o.into_mut(); *last_used = tick; - model + ( + match model { + FigureModelEntryFuture::Pending(recv) => { + if let Some(MeshWorkerResponse { + col_light, + opaque, + bounds, + vertex_range, + }) = Arc::get_mut(recv).take().and_then(|cell| cell.take()) + { + // FIXME: We really need to stop hard failing on failure to upload + // to the GPU. + let model_entry = col_lights + .create_figure( + renderer, + col_light, + (opaque, bounds), + vertex_range, + ) + .expect("Failed to upload figure data to the GPU!"); + *model = FigureModelEntryFuture::Done(model_entry); + // NOTE: Borrow checker isn't smart enough to figure this out. + if let FigureModelEntryFuture::Done(model) = model { + Some(model) + } else { + unreachable!(); + } + } else { + None + } + }, + FigureModelEntryFuture::Done(model) => Some(model), + }, + skel, + ) }, Entry::Vacant(v) => { - let key = v.key(); - let model = { - let skeleton_attr = (&body) - .try_into() - .ok() - .unwrap_or_else(::default); + let key = v.key().clone(); + let slot = Arc::new(atomic::AtomicCell::new(None)); + let manifests = Arc::clone(&self.manifests); + let slot_ = Arc::clone(&slot); - let manifest_indicator = &mut self.manifest_indicator; + thread_pool.execute(move || { + let manifests = &*manifests; let mut greedy = FigureModel::make_greedy(); let mut opaque = Mesh::::new(); // Choose the most conservative bounds for any LOD model. @@ -1045,10 +387,13 @@ impl FigureModelCache { ) -> _| { let vertex_start = opaque.vertices().len(); - let meshes = - Self::bone_meshes(key, manifest_indicator, |segment, offset| { + let meshes = ::bone_meshes( + &key, + &*manifests, + |segment, offset| { generate_mesh(&mut greedy, &mut opaque, segment, offset) - }); + }, + ); meshes .iter() .enumerate() @@ -1153,24 +498,36 @@ impl FigureModelCache { make_model(generate_mesh_lod_mid), make_model(generate_mesh_lod_low), ]; - ( - col_lights - .create_figure(renderer, greedy, (opaque, figure_bounds), models) - .expect("Failed to upload figure data to the GPU!"), - skeleton_attr, - ) - }; - &v.insert((model, tick)).0 + + slot_.store(Some(MeshWorkerResponse { + col_light: greedy.finalize(), + opaque, + bounds: figure_bounds, + vertex_range: models, + })); + }); + + let skel = &(v + .insert(((FigureModelEntryFuture::Pending(slot), skeleton_attr), tick)) + .0) + .1; + (None, skel) }, } } - pub fn clean(&mut self, col_lights: &mut super::FigureColLights, tick: u64) { + pub fn clean(&mut self, col_lights: &mut super::FigureColLights, tick: u64) + where + ::Spec: Clone, + { // Check for reloaded manifests // TODO: maybe do this in a different function, maintain? if self.manifest_indicator.reloaded() { col_lights.atlas.clear(); self.models.clear(); + if let Err(err) = ::reload(Arc::make_mut(&mut self.manifests)) { + tracing::warn!(?err, "Hot reload failed."); + } } // TODO: Don't hard-code this. if tick % 60 == 0 { @@ -1179,7 +536,9 @@ impl FigureModelCache { let delta = 60 * 60; let alive = *last_used + delta > tick; if !alive { - col_lights.atlas.deallocate(model_entry.allocation.id); + if let FigureModelEntryFuture::Done(model_entry) = model_entry { + col_lights.atlas.deallocate(model_entry.allocation.id); + } } alive }); diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index ca372ef6bd..2a622d9103 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -1,41 +1,42 @@ +use super::cache::FigureKey; use crate::render::{BoneMeshes, Mesh}; use common::{ - assets::{self, watch::ReloadIndicator, Asset}, + assets::{self, watch::ReloadIndicator, Asset, AssetWith, Ron}, comp::{ - biped_large::{BodyType as BLBodyType, Species as BLSpecies}, - bird_medium::{BodyType as BMBodyType, Species as BMSpecies}, + biped_large::{self, BodyType as BLBodyType, Species as BLSpecies}, + bird_medium::{self, BodyType as BMBodyType, Species as BMSpecies}, bird_small, - critter::{BodyType as CBodyType, Species as CSpecies}, - dragon::{BodyType as DBodyType, Species as DSpecies}, + critter::{self, BodyType as CBodyType, Species as CSpecies}, + dragon::{self, BodyType as DBodyType, Species as DSpecies}, fish_medium, fish_small, - golem::{BodyType as GBodyType, Species as GSpecies}, + golem::{self, BodyType as GBodyType, Species as GSpecies}, humanoid::{self, Body, BodyType, EyeColor, Skin, Species}, item::tool::ToolKind, object, - quadruped_low::{BodyType as QLBodyType, Species as QLSpecies}, - quadruped_medium::{BodyType as QMBodyType, Species as QMSpecies}, - quadruped_small::{BodyType as QSBodyType, Species as QSSpecies}, + quadruped_low::{self, BodyType as QLBodyType, Species as QLSpecies}, + quadruped_medium::{self, BodyType as QMBodyType, Species as QMSpecies}, + quadruped_small::{self, BodyType as QSBodyType, Species as QSSpecies}, }, figure::{DynaUnionizer, MatSegment, Material, Segment}, }; use dot_vox::DotVoxData; use hashbrown::HashMap; -use serde_derive::{Deserialize, Serialize}; -use std::{fs::File, io::BufReader, sync::Arc}; +use serde_derive::Deserialize; +use std::sync::Arc; use tracing::{error, warn}; use vek::*; fn load_segment(mesh_name: &str) -> Segment { let full_specifier: String = ["voxygen.voxel.", mesh_name].concat(); - Segment::from(assets::load_expect::(full_specifier.as_str()).as_ref()) + Segment::from(DotVoxData::load_expect(full_specifier.as_str()).as_ref()) } fn graceful_load_vox(mesh_name: &str) -> Arc { let full_specifier: String = ["voxygen.voxel.", mesh_name].concat(); - match assets::load::(full_specifier.as_str()) { + match DotVoxData::load(full_specifier.as_str()) { Ok(dot_vox) => dot_vox, Err(_) => { error!(?full_specifier, "Could not load vox file for figure"); - assets::load_expect::("voxygen.voxel.not_found") + DotVoxData::load_expect("voxygen.voxel.not_found") }, } } @@ -74,37 +75,96 @@ fn recolor_grey(rgb: Rgb, color: Rgb) -> Rgb { } } +/// A set of reloadable specifications for a Body. +pub trait BodySpec: Sized { + type Spec; + + /// Initialize all the specifications for this Body and watch for changes. + fn load_watched(indicator: &mut ReloadIndicator) -> Result; + + /// Reload all specifications for this Body (to be called if the reload + /// indicator is set). + fn reload(spec: &mut Self::Spec) -> Result<(), assets::Error>; + + /// Mesh bones using the given spec, character state, and mesh generation + /// function. + /// + /// NOTE: We deliberately call this function with only the key into the + /// cache, to enforce that the cached state only depends on the key. We + /// may end up using a mechanism different from this cache eventually, + /// in which case this strategy might change. + fn bone_meshes( + key: &FigureKey, + spec: &Self::Spec, + generate_mesh: impl FnMut(Segment, Vec3) -> BoneMeshes, + ) -> [Option; anim::MAX_BONE_COUNT]; +} + +macro_rules! make_vox_spec { + ( + $body:ty, + struct $Spec:ident { $( $(+)? $field:ident: $ty:ty = $asset_path:literal),* $(,)? }, + |$self_pat:pat, $spec_pat:pat, $generate_mesh:pat| $bone_meshes:block $(,)? + ) => { + #[derive(Clone)] + pub struct $Spec { + $( $field: AssetWith, $asset_path>, )* + } + + impl BodySpec for $body { + type Spec = $Spec; + + #[allow(unused_variables)] + fn load_watched(indicator: &mut ReloadIndicator) -> Result { + Ok(Self::Spec { + $( $field: AssetWith::load_watched(indicator)?, )* + }) + } + + #[allow(unused_variables)] + fn reload(spec: &mut Self::Spec) -> Result<(), assets::Error> { + $( spec.$field.reload()?; )* + Ok(()) + } + + fn bone_meshes( + $self_pat: &FigureKey, + $spec_pat: &Self::Spec, + $generate_mesh: impl FnMut(Segment, Vec3) -> BoneMeshes, + ) -> [Option; anim::MAX_BONE_COUNT] { + $bone_meshes + } + } + } +} + // All offsets should be relative to an initial origin that doesn't change when // combining segments -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct VoxSpec(String, [T; 3]); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct VoxSimple(String); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct ArmorVoxSpec { vox_spec: VoxSpec, color: Option<[u8; 3]>, } // For use by armor with a left and right component -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedArmorVoxSpec { left: ArmorVoxSpec, right: ArmorVoxSpec, + /// FIXME: Either use this, or remove it. + #[allow(dead_code)] color: Option<[u8; 3]>, } -#[derive(Serialize, Deserialize)] -struct MobSidedVoxSpec { - left: ArmorVoxSpec, - right: ArmorVoxSpec, -} - /// Color information not found in voxels, for humanoids. -#[derive(Serialize, Deserialize)] -pub struct HumColorSpec { +#[derive(Deserialize)] +struct HumColorSpec { hair_colors: humanoid::species::PureCases>, eye_colors_light: humanoid::eye_color::PureCases<(u8, u8, u8)>, eye_colors_dark: humanoid::eye_color::PureCases<(u8, u8, u8)>, @@ -114,19 +174,7 @@ pub struct HumColorSpec { skin_colors_dark: humanoid::skin::PureCases<(u8, u8, u8)>, } -impl Asset for HumColorSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - impl HumColorSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_color_manifest", indicator).unwrap() - } - fn hair_color(&self, species: Species, val: u8) -> (u8, u8, u8) { species .elim_case_pure(&self.hair_colors) @@ -160,7 +208,7 @@ impl HumColorSpec { } // All reliant on humanoid::Species and humanoid::BodyType -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct HumHeadSubSpec { offset: [f32; 3], // Should be relative to initial origin head: VoxSpec, @@ -169,23 +217,11 @@ struct HumHeadSubSpec { beard: Vec>>, accessory: Vec>>, } -#[derive(Serialize, Deserialize)] -pub struct HumHeadSpec(HashMap<(Species, BodyType), HumHeadSubSpec>); - -impl Asset for HumHeadSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +#[derive(Deserialize)] +struct HumHeadSpec(HashMap<(Species, BodyType), HumHeadSubSpec>); impl HumHeadSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_head_manifest", indicator).unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, body: &Body, color_spec: &HumColorSpec, @@ -278,121 +314,182 @@ impl HumHeadSpec { // Armor aspects should be in the same order, top to bottom. // These seem overly split up, but wanted to keep the armor seperated // unlike head which is done above. -#[derive(Serialize, Deserialize)] -pub struct ArmorVoxSpecMap +#[derive(Deserialize)] +struct ArmorVoxSpecMap where K: std::hash::Hash + std::cmp::Eq, { default: S, map: HashMap, } -#[derive(Serialize, Deserialize)] -pub struct HumArmorShoulderSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorChestSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorHandSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorBeltSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorBackSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorPantsSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorFootSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumMainWeaponSpec(HashMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorLanternSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorHeadSpec(ArmorVoxSpecMap); -#[derive(Serialize, Deserialize)] -pub struct HumArmorTabardSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorShoulderSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorChestSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorHandSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorBeltSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorBackSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorPantsSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorFootSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumMainWeaponSpec(HashMap); +#[derive(Deserialize)] +struct HumArmorLanternSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorHeadSpec(ArmorVoxSpecMap); +#[derive(Deserialize)] +struct HumArmorTabardSpec(ArmorVoxSpecMap); -impl Asset for HumArmorShoulderSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; +make_vox_spec!( + Body, + struct HumSpec { + color: HumColorSpec = "voxygen.voxel.humanoid_color_manifest", + head: HumHeadSpec = "voxygen.voxel.humanoid_head_manifest", + armor_shoulder: HumArmorShoulderSpec = "voxygen.voxel.humanoid_armor_shoulder_manifest", + armor_chest: HumArmorChestSpec = "voxygen.voxel.humanoid_armor_chest_manifest", + armor_hand: HumArmorHandSpec = "voxygen.voxel.humanoid_armor_hand_manifest", + armor_belt: HumArmorBeltSpec = "voxygen.voxel.humanoid_armor_belt_manifest", + armor_back: HumArmorBackSpec = "voxygen.voxel.humanoid_armor_back_manifest", + armor_pants: HumArmorPantsSpec = "voxygen.voxel.humanoid_armor_pants_manifest", + armor_foot: HumArmorFootSpec = "voxygen.voxel.humanoid_armor_foot_manifest", + main_weapon: HumMainWeaponSpec = "voxygen.voxel.humanoid_main_weapon_manifest", + armor_lantern: HumArmorLanternSpec = "voxygen.voxel.humanoid_lantern_manifest", + // TODO: Add these. + /* armor_head: HumArmorHeadSpec = "voxygen.voxel.humanoid_armor_head_manifest", + tabard: HumArmorTabardSpec = "voxygen.voxel.humanoid_armor_tabard_manifest", */ + }, + |FigureKey { body, extra }, spec, mut generate_mesh| { + const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey { + third_person: None, + tool: None, + lantern: None, + hand: None, + foot: None, + }; - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorChestSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; + // TODO: This is bad code, maybe this method should return Option<_> + let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT); + let third_person = loadout.third_person.as_ref(); + let tool = loadout.tool.as_ref(); + let lantern = loadout.lantern.as_deref(); + let hand = loadout.hand.as_deref(); + let foot = loadout.foot.as_deref(); - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorHandSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; + [ + third_person.map(|_| { + spec.head.asset.mesh_head( + body, + &spec.color.asset, + |segment, offset| generate_mesh(segment, offset), + ) + }), + third_person.map(|loadout| { + spec.armor_chest.asset.mesh_chest( + body, + &spec.color.asset, + loadout.chest.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + third_person.map(|loadout| { + spec.armor_belt.asset.mesh_belt( + body, + &spec.color.asset, + loadout.belt.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + third_person.map(|loadout| { + spec.armor_back.asset.mesh_back( + body, + &spec.color.asset, + loadout.back.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + third_person.map(|loadout| { + spec.armor_pants.asset.mesh_pants( + body, + &spec.color.asset, + loadout.pants.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + Some(spec.armor_hand.asset.mesh_left_hand( + body, + &spec.color.asset, + hand, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.armor_hand.asset.mesh_right_hand( + body, + &spec.color.asset, + hand, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.armor_foot.asset.mesh_left_foot( + body, + &spec.color.asset, + foot, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.armor_foot.asset.mesh_right_foot( + body, + &spec.color.asset, + foot, + |segment, offset| generate_mesh(segment, offset), + )), + third_person.map(|loadout| { + spec.armor_shoulder.asset.mesh_left_shoulder( + body, + &spec.color.asset, + loadout.shoulder.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + third_person.map(|loadout| { + spec.armor_shoulder.asset.mesh_right_shoulder( + body, + &spec.color.asset, + loadout.shoulder.as_deref(), + |segment, offset| generate_mesh(segment, offset), + ) + }), + Some(mesh_glider(|segment, offset| { + generate_mesh(segment, offset) + })), + tool.map(|tool| { + spec.main_weapon.asset.mesh_main_weapon( + tool.active.as_ref(), + false, + |segment, offset| generate_mesh(segment, offset), + ) + }), + tool.map(|tool| { + spec.main_weapon.asset.mesh_main_weapon( + tool.second.as_ref(), + true, + |segment, offset| generate_mesh(segment, offset), + ) + }), + Some(spec.armor_lantern.asset.mesh_lantern( + body, + &spec.color.asset, + lantern, + |segment, offset| generate_mesh(segment, offset), + )), + Some(mesh_hold(|segment, offset| generate_mesh(segment, offset))), + ] + }, +); - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorBeltSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorBackSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorPantsSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorFootSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorLanternSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorHeadSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumArmorTabardSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} -impl Asset for HumMainWeaponSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} // Shoulder impl HumArmorShoulderSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_shoulder_manifest", indicator) - .unwrap() - } - fn mesh_shoulder( &self, body: &Body, @@ -448,7 +545,7 @@ impl HumArmorShoulderSpec { generate_mesh(shoulder_segment, Vec3::from(offset)) } - pub fn mesh_left_shoulder( + fn mesh_left_shoulder( &self, body: &Body, color_spec: &HumColorSpec, @@ -458,7 +555,7 @@ impl HumArmorShoulderSpec { self.mesh_shoulder(body, color_spec, shoulder, true, generate_mesh) } - pub fn mesh_right_shoulder( + fn mesh_right_shoulder( &self, body: &Body, color_spec: &HumColorSpec, @@ -470,12 +567,7 @@ impl HumArmorShoulderSpec { } // Chest impl HumArmorChestSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_chest_manifest", indicator) - .unwrap() - } - - pub fn mesh_chest( + fn mesh_chest( &self, body: &Body, color_spec: &HumColorSpec, @@ -523,11 +615,6 @@ impl HumArmorChestSpec { } // Hand impl HumArmorHandSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_hand_manifest", indicator) - .unwrap() - } - fn mesh_hand( &self, body: &Body, @@ -577,7 +664,7 @@ impl HumArmorHandSpec { generate_mesh(hand_segment, Vec3::from(offset)) } - pub fn mesh_left_hand( + fn mesh_left_hand( &self, body: &Body, color_spec: &HumColorSpec, @@ -587,7 +674,7 @@ impl HumArmorHandSpec { self.mesh_hand(body, color_spec, hand, true, generate_mesh) } - pub fn mesh_right_hand( + fn mesh_right_hand( &self, body: &Body, color_spec: &HumColorSpec, @@ -599,12 +686,7 @@ impl HumArmorHandSpec { } // Belt impl HumArmorBeltSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_belt_manifest", indicator) - .unwrap() - } - - pub fn mesh_belt( + fn mesh_belt( &self, body: &Body, color_spec: &HumColorSpec, @@ -640,12 +722,7 @@ impl HumArmorBeltSpec { } // Cape impl HumArmorBackSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_back_manifest", indicator) - .unwrap() - } - - pub fn mesh_back( + fn mesh_back( &self, body: &Body, color_spec: &HumColorSpec, @@ -680,12 +757,7 @@ impl HumArmorBackSpec { } // Legs impl HumArmorPantsSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_pants_manifest", indicator) - .unwrap() - } - - pub fn mesh_pants( + fn mesh_pants( &self, body: &Body, color_spec: &HumColorSpec, @@ -733,11 +805,6 @@ impl HumArmorPantsSpec { } // Foot impl HumArmorFootSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_foot_manifest", indicator) - .unwrap() - } - fn mesh_foot( &self, body: &Body, @@ -777,7 +844,7 @@ impl HumArmorFootSpec { generate_mesh(foot_segment, Vec3::from(spec.vox_spec.1)) } - pub fn mesh_left_foot( + fn mesh_left_foot( &self, body: &Body, color_spec: &HumColorSpec, @@ -787,7 +854,7 @@ impl HumArmorFootSpec { self.mesh_foot(body, color_spec, foot, true, generate_mesh) } - pub fn mesh_right_foot( + fn mesh_right_foot( &self, body: &Body, color_spec: &HumColorSpec, @@ -799,12 +866,7 @@ impl HumArmorFootSpec { } impl HumMainWeaponSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_main_weapon_manifest", indicator) - .unwrap() - } - - pub fn mesh_main_weapon( + fn mesh_main_weapon( &self, tool_kind: Option<&ToolKind>, flipped: bool, @@ -848,11 +910,7 @@ impl HumMainWeaponSpec { // Lantern impl HumArmorLanternSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_lantern_manifest", indicator).unwrap() - } - - pub fn mesh_lantern( + fn mesh_lantern( &self, body: &Body, color_spec: &HumColorSpec, @@ -887,12 +945,9 @@ impl HumArmorLanternSpec { } } impl HumArmorHeadSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_head_manifest", indicator) - .unwrap() - } - - pub fn mesh_head( + /// FIXME: Either use this, or remove it. + #[allow(dead_code)] + fn mesh_head( &self, body: &Body, color_spec: &HumColorSpec, @@ -939,12 +994,9 @@ impl HumArmorHeadSpec { } } impl HumArmorTabardSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.humanoid_armor_tabard_manifest", indicator) - .unwrap() - } - - pub fn mesh_tabard( + /// FIXME: Either use this, or remove it. + #[allow(dead_code)] + fn mesh_tabard( &self, body: &Body, color_spec: &HumColorSpec, @@ -991,7 +1043,7 @@ impl HumArmorTabardSpec { } } // TODO: Inventory -pub fn mesh_glider(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) -> BoneMeshes { +fn mesh_glider(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) -> BoneMeshes { load_mesh( "object.glider", Vec3::new(-26.0, -26.0, -5.0), @@ -999,7 +1051,7 @@ pub fn mesh_glider(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) ) } -pub fn mesh_hold(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) -> BoneMeshes { +fn mesh_hold(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) -> BoneMeshes { load_mesh( "weapon.projectile.simple-arrow", Vec3::new(-0.5, -6.0, -1.5), @@ -1008,60 +1060,95 @@ pub fn mesh_hold(generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes) - } ///////// -#[derive(Serialize, Deserialize)] -pub struct QuadrupedSmallCentralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSCentralVoxSpec>); +#[derive(Deserialize)] +struct QuadrupedSmallCentralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSCentralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedQSCentralVoxSpec { head: QuadrupedSmallCentralSubSpec, chest: QuadrupedSmallCentralSubSpec, tail: QuadrupedSmallCentralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedSmallCentralSubSpec { offset: [f32; 3], // Should be relative to initial origin central: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct QuadrupedSmallLateralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSLateralVoxSpec>); +#[derive(Deserialize)] +struct QuadrupedSmallLateralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedQSLateralVoxSpec { left_front: QuadrupedSmallLateralSubSpec, right_front: QuadrupedSmallLateralSubSpec, left_back: QuadrupedSmallLateralSubSpec, right_back: QuadrupedSmallLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedSmallLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for QuadrupedSmallCentralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for QuadrupedSmallLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + quadruped_small::Body, + struct QuadrupedSmallSpec { + central: QuadrupedSmallCentralSpec = "voxygen.voxel.quadruped_small_central_manifest", + lateral: QuadrupedSmallLateralSpec = "voxygen.voxel.quadruped_small_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.central.asset.mesh_head( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_chest( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fr( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_bl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_br( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_tail( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); impl QuadrupedSmallCentralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_small_central_manifest", indicator) - .unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, species: QSSpecies, body_type: QSBodyType, @@ -1082,7 +1169,7 @@ impl QuadrupedSmallCentralSpec { generate_mesh(central, Vec3::from(spec.head.offset)) } - pub fn mesh_chest( + fn mesh_chest( &self, species: QSSpecies, body_type: QSBodyType, @@ -1103,7 +1190,7 @@ impl QuadrupedSmallCentralSpec { generate_mesh(central, Vec3::from(spec.chest.offset)) } - pub fn mesh_tail( + fn mesh_tail( &self, species: QSSpecies, body_type: QSBodyType, @@ -1126,12 +1213,7 @@ impl QuadrupedSmallCentralSpec { } impl QuadrupedSmallLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_small_lateral_manifest", indicator) - .unwrap() - } - - pub fn mesh_foot_fl( + fn mesh_foot_fl( &self, species: QSSpecies, body_type: QSBodyType, @@ -1152,7 +1234,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(lateral, Vec3::from(spec.left_front.offset)) } - pub fn mesh_foot_fr( + fn mesh_foot_fr( &self, species: QSSpecies, body_type: QSBodyType, @@ -1173,7 +1255,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(lateral, Vec3::from(spec.right_front.offset)) } - pub fn mesh_foot_bl( + fn mesh_foot_bl( &self, species: QSSpecies, body_type: QSBodyType, @@ -1194,7 +1276,7 @@ impl QuadrupedSmallLateralSpec { generate_mesh(lateral, Vec3::from(spec.left_back.offset)) } - pub fn mesh_foot_br( + fn mesh_foot_br( &self, species: QSSpecies, body_type: QSBodyType, @@ -1217,10 +1299,10 @@ impl QuadrupedSmallLateralSpec { } ////// -#[derive(Serialize, Deserialize)] -pub struct QuadrupedMediumCentralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMCentralVoxSpec>); +#[derive(Deserialize)] +struct QuadrupedMediumCentralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMCentralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedQMCentralVoxSpec { upper: QuadrupedMediumCentralSubSpec, lower: QuadrupedMediumCentralSubSpec, @@ -1230,15 +1312,15 @@ struct SidedQMCentralVoxSpec { torso_back: QuadrupedMediumCentralSubSpec, tail: QuadrupedMediumCentralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedMediumCentralSubSpec { offset: [f32; 3], // Should be relative to initial origin central: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct QuadrupedMediumLateralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] +struct QuadrupedMediumLateralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMLateralVoxSpec>); +#[derive(Deserialize)] struct SidedQMLateralVoxSpec { leg_fl: QuadrupedMediumLateralSubSpec, leg_fr: QuadrupedMediumLateralSubSpec, @@ -1249,35 +1331,102 @@ struct SidedQMLateralVoxSpec { foot_bl: QuadrupedMediumLateralSubSpec, foot_br: QuadrupedMediumLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedMediumLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for QuadrupedMediumCentralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) +make_vox_spec!( + quadruped_medium::Body, + struct QuadrupedMediumSpec { + central: QuadrupedMediumCentralSpec = "voxygen.voxel.quadruped_medium_central_manifest", + lateral: QuadrupedMediumLateralSpec = "voxygen.voxel.quadruped_medium_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.central.asset.mesh_head_upper( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_head_lower( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_jaw( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_tail( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_torso_front( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_torso_back( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_ears( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_fl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_fr( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_bl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_br( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fr( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_bl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_br( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + ] } -} - -impl Asset for QuadrupedMediumLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +); impl QuadrupedMediumCentralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_medium_central_manifest", indicator) - .unwrap() - } - - pub fn mesh_head_upper( + fn mesh_head_upper( &self, species: QMSpecies, body_type: QMBodyType, @@ -1298,7 +1447,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.upper.offset)) } - pub fn mesh_head_lower( + fn mesh_head_lower( &self, species: QMSpecies, body_type: QMBodyType, @@ -1319,7 +1468,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.lower.offset)) } - pub fn mesh_jaw( + fn mesh_jaw( &self, species: QMSpecies, body_type: QMBodyType, @@ -1340,7 +1489,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.jaw.offset)) } - pub fn mesh_ears( + fn mesh_ears( &self, species: QMSpecies, body_type: QMBodyType, @@ -1361,7 +1510,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.ears.offset)) } - pub fn mesh_torso_front( + fn mesh_torso_front( &self, species: QMSpecies, body_type: QMBodyType, @@ -1382,7 +1531,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.torso_front.offset)) } - pub fn mesh_torso_back( + fn mesh_torso_back( &self, species: QMSpecies, body_type: QMBodyType, @@ -1403,7 +1552,7 @@ impl QuadrupedMediumCentralSpec { generate_mesh(central, Vec3::from(spec.torso_back.offset)) } - pub fn mesh_tail( + fn mesh_tail( &self, species: QMSpecies, body_type: QMBodyType, @@ -1426,12 +1575,7 @@ impl QuadrupedMediumCentralSpec { } impl QuadrupedMediumLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_medium_lateral_manifest", indicator) - .unwrap() - } - - pub fn mesh_leg_fl( + fn mesh_leg_fl( &self, species: QMSpecies, body_type: QMBodyType, @@ -1452,7 +1596,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_fl.offset)) } - pub fn mesh_leg_fr( + fn mesh_leg_fr( &self, species: QMSpecies, body_type: QMBodyType, @@ -1473,7 +1617,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_fr.offset)) } - pub fn mesh_leg_bl( + fn mesh_leg_bl( &self, species: QMSpecies, body_type: QMBodyType, @@ -1494,7 +1638,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_bl.offset)) } - pub fn mesh_leg_br( + fn mesh_leg_br( &self, species: QMSpecies, body_type: QMBodyType, @@ -1515,7 +1659,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_br.offset)) } - pub fn mesh_foot_fl( + fn mesh_foot_fl( &self, species: QMSpecies, body_type: QMBodyType, @@ -1536,7 +1680,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_fl.offset)) } - pub fn mesh_foot_fr( + fn mesh_foot_fr( &self, species: QMSpecies, body_type: QMBodyType, @@ -1557,7 +1701,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_fr.offset)) } - pub fn mesh_foot_bl( + fn mesh_foot_bl( &self, species: QMSpecies, body_type: QMBodyType, @@ -1578,7 +1722,7 @@ impl QuadrupedMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_bl.offset)) } - pub fn mesh_foot_br( + fn mesh_foot_br( &self, species: QMSpecies, body_type: QMBodyType, @@ -1601,60 +1745,95 @@ impl QuadrupedMediumLateralSpec { } //// -#[derive(Serialize, Deserialize)] -pub struct BirdMediumCenterSpec(HashMap<(BMSpecies, BMBodyType), SidedBMCenterVoxSpec>); +#[derive(Deserialize)] +struct BirdMediumCenterSpec(HashMap<(BMSpecies, BMBodyType), SidedBMCenterVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedBMCenterVoxSpec { head: BirdMediumCenterSubSpec, torso: BirdMediumCenterSubSpec, tail: BirdMediumCenterSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct BirdMediumCenterSubSpec { offset: [f32; 3], // Should be relative to initial origin center: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct BirdMediumLateralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMLateralVoxSpec>); +#[derive(Deserialize)] +struct BirdMediumLateralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedBMLateralVoxSpec { wing_l: BirdMediumLateralSubSpec, wing_r: BirdMediumLateralSubSpec, foot_l: BirdMediumLateralSubSpec, foot_r: BirdMediumLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct BirdMediumLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for BirdMediumCenterSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for BirdMediumLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + bird_medium::Body, + struct BirdMediumSpec { + center: BirdMediumCenterSpec = "voxygen.voxel.bird_medium_center_manifest", + lateral: BirdMediumLateralSpec = "voxygen.voxel.bird_medium_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.center.asset.mesh_head( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_torso( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_tail( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); impl BirdMediumCenterSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.bird_medium_center_manifest", indicator) - .unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, species: BMSpecies, body_type: BMBodyType, @@ -1675,7 +1854,7 @@ impl BirdMediumCenterSpec { generate_mesh(center, Vec3::from(spec.head.offset)) } - pub fn mesh_torso( + fn mesh_torso( &self, species: BMSpecies, body_type: BMBodyType, @@ -1696,7 +1875,7 @@ impl BirdMediumCenterSpec { generate_mesh(center, Vec3::from(spec.torso.offset)) } - pub fn mesh_tail( + fn mesh_tail( &self, species: BMSpecies, body_type: BMBodyType, @@ -1718,12 +1897,7 @@ impl BirdMediumCenterSpec { } } impl BirdMediumLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.bird_medium_lateral_manifest", indicator) - .unwrap() - } - - pub fn mesh_wing_l( + fn mesh_wing_l( &self, species: BMSpecies, body_type: BMBodyType, @@ -1744,7 +1918,7 @@ impl BirdMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_l.offset)) } - pub fn mesh_wing_r( + fn mesh_wing_r( &self, species: BMSpecies, body_type: BMBodyType, @@ -1765,7 +1939,7 @@ impl BirdMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_r.offset)) } - pub fn mesh_foot_l( + fn mesh_foot_l( &self, species: BMSpecies, body_type: BMBodyType, @@ -1786,7 +1960,7 @@ impl BirdMediumLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_l.offset)) } - pub fn mesh_foot_r( + fn mesh_foot_r( &self, species: BMSpecies, body_type: BMBodyType, @@ -1808,10 +1982,10 @@ impl BirdMediumLateralSpec { } } //// -#[derive(Serialize, Deserialize)] -pub struct CritterCenterSpec(HashMap<(CSpecies, CBodyType), SidedCCenterVoxSpec>); +#[derive(Deserialize)] +struct CritterCenterSpec(HashMap<(CSpecies, CBodyType), SidedCCenterVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedCCenterVoxSpec { head: CritterCenterSubSpec, chest: CritterCenterSubSpec, @@ -1819,26 +1993,61 @@ struct SidedCCenterVoxSpec { feet_b: CritterCenterSubSpec, tail: CritterCenterSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct CritterCenterSubSpec { offset: [f32; 3], // Should be relative to initial origin center: VoxSimple, } -impl Asset for CritterCenterSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + critter::Body, + struct CritterSpec { + center: CritterCenterSpec = "voxygen.voxel.critter_center_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.center.asset.mesh_head( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_chest( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_feet_f( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_feet_b( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_tail( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); impl CritterCenterSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.critter_center_manifest", indicator).unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, species: CSpecies, body_type: CBodyType, @@ -1859,7 +2068,7 @@ impl CritterCenterSpec { generate_mesh(center, Vec3::from(spec.head.offset)) } - pub fn mesh_chest( + fn mesh_chest( &self, species: CSpecies, body_type: CBodyType, @@ -1880,7 +2089,7 @@ impl CritterCenterSpec { generate_mesh(center, Vec3::from(spec.chest.offset)) } - pub fn mesh_feet_f( + fn mesh_feet_f( &self, species: CSpecies, body_type: CBodyType, @@ -1901,7 +2110,7 @@ impl CritterCenterSpec { generate_mesh(center, Vec3::from(spec.feet_f.offset)) } - pub fn mesh_feet_b( + fn mesh_feet_b( &self, species: CSpecies, body_type: CBodyType, @@ -1922,7 +2131,7 @@ impl CritterCenterSpec { generate_mesh(center, Vec3::from(spec.feet_b.offset)) } - pub fn mesh_tail( + fn mesh_tail( &self, species: CSpecies, body_type: CBodyType, @@ -1944,7 +2153,44 @@ impl CritterCenterSpec { } } //// -pub fn mesh_fish_medium_head( +make_vox_spec!( + fish_medium::Body, + struct FishMediumSpec {}, + |FigureKey { body, .. }, _spec, mut generate_mesh| { + [ + Some(mesh_fish_medium_head(body.head, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_medium_torso(body.torso, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_medium_rear(body.rear, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_medium_tail(body.tail, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_medium_fin_l(body.fin_l, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_medium_fin_r(body.fin_r, |segment, offset| { + generate_mesh(segment, offset) + })), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); + +fn mesh_fish_medium_head( head: fish_medium::Head, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -1957,7 +2203,7 @@ pub fn mesh_fish_medium_head( ) } -pub fn mesh_fish_medium_torso( +fn mesh_fish_medium_torso( torso: fish_medium::Torso, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -1970,7 +2216,7 @@ pub fn mesh_fish_medium_torso( ) } -pub fn mesh_fish_medium_rear( +fn mesh_fish_medium_rear( rear: fish_medium::Rear, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -1983,7 +2229,7 @@ pub fn mesh_fish_medium_rear( ) } -pub fn mesh_fish_medium_tail( +fn mesh_fish_medium_tail( tail: fish_medium::Tail, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -1996,7 +2242,7 @@ pub fn mesh_fish_medium_tail( ) } -pub fn mesh_fish_medium_fin_l( +fn mesh_fish_medium_fin_l( fin_l: fish_medium::FinL, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2009,7 +2255,7 @@ pub fn mesh_fish_medium_fin_l( ) } -pub fn mesh_fish_medium_fin_r( +fn mesh_fish_medium_fin_r( fin_r: fish_medium::FinR, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2024,10 +2270,10 @@ pub fn mesh_fish_medium_fin_r( //// -#[derive(Serialize, Deserialize)] -pub struct DragonCenterSpec(HashMap<(DSpecies, DBodyType), SidedDCenterVoxSpec>); +#[derive(Deserialize)] +struct DragonCenterSpec(HashMap<(DSpecies, DBodyType), SidedDCenterVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedDCenterVoxSpec { upper: DragonCenterSubSpec, lower: DragonCenterSubSpec, @@ -2037,16 +2283,16 @@ struct SidedDCenterVoxSpec { tail_front: DragonCenterSubSpec, tail_rear: DragonCenterSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct DragonCenterSubSpec { offset: [f32; 3], // Should be relative to initial origin center: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>); +#[derive(Deserialize)] +struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedDLateralVoxSpec { wing_in_l: DragonLateralSubSpec, wing_in_r: DragonLateralSubSpec, @@ -2057,34 +2303,102 @@ struct SidedDLateralVoxSpec { foot_bl: DragonLateralSubSpec, foot_br: DragonLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct DragonLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for DragonCenterSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for DragonLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + dragon::Body, + struct DragonSpec { + center: DragonCenterSpec = "voxygen.voxel.dragon_center_manifest", + lateral: DragonLateralSpec = "voxygen.voxel.dragon_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.center.asset.mesh_head_upper( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_head_lower( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_jaw( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_chest_front( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_chest_rear( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_tail_front( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_tail_rear( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_in_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_in_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_out_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_wing_out_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fr( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_bl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_br( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + ] + }, +); impl DragonCenterSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.dragon_center_manifest", indicator).unwrap() - } - - pub fn mesh_head_upper( + fn mesh_head_upper( &self, species: DSpecies, body_type: DBodyType, @@ -2105,7 +2419,7 @@ impl DragonCenterSpec { generate_mesh(central, Vec3::from(spec.upper.offset)) } - pub fn mesh_head_lower( + fn mesh_head_lower( &self, species: DSpecies, body_type: DBodyType, @@ -2126,7 +2440,7 @@ impl DragonCenterSpec { generate_mesh(central, Vec3::from(spec.lower.offset)) } - pub fn mesh_jaw( + fn mesh_jaw( &self, species: DSpecies, body_type: DBodyType, @@ -2147,7 +2461,7 @@ impl DragonCenterSpec { generate_mesh(central, Vec3::from(spec.jaw.offset)) } - pub fn mesh_chest_front( + fn mesh_chest_front( &self, species: DSpecies, body_type: DBodyType, @@ -2168,7 +2482,7 @@ impl DragonCenterSpec { generate_mesh(center, Vec3::from(spec.chest_front.offset)) } - pub fn mesh_chest_rear( + fn mesh_chest_rear( &self, species: DSpecies, body_type: DBodyType, @@ -2189,7 +2503,7 @@ impl DragonCenterSpec { generate_mesh(center, Vec3::from(spec.chest_rear.offset)) } - pub fn mesh_tail_front( + fn mesh_tail_front( &self, species: DSpecies, body_type: DBodyType, @@ -2210,7 +2524,7 @@ impl DragonCenterSpec { generate_mesh(center, Vec3::from(spec.tail_front.offset)) } - pub fn mesh_tail_rear( + fn mesh_tail_rear( &self, species: DSpecies, body_type: DBodyType, @@ -2232,11 +2546,7 @@ impl DragonCenterSpec { } } impl DragonLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.dragon_lateral_manifest", indicator).unwrap() - } - - pub fn mesh_wing_in_l( + fn mesh_wing_in_l( &self, species: DSpecies, body_type: DBodyType, @@ -2257,7 +2567,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_in_l.offset)) } - pub fn mesh_wing_in_r( + fn mesh_wing_in_r( &self, species: DSpecies, body_type: DBodyType, @@ -2278,7 +2588,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_in_r.offset)) } - pub fn mesh_wing_out_l( + fn mesh_wing_out_l( &self, species: DSpecies, body_type: DBodyType, @@ -2299,7 +2609,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_out_l.offset)) } - pub fn mesh_wing_out_r( + fn mesh_wing_out_r( &self, species: DSpecies, body_type: DBodyType, @@ -2320,7 +2630,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.wing_out_r.offset)) } - pub fn mesh_foot_fl( + fn mesh_foot_fl( &self, species: DSpecies, body_type: DBodyType, @@ -2341,7 +2651,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_fl.offset)) } - pub fn mesh_foot_fr( + fn mesh_foot_fr( &self, species: DSpecies, body_type: DBodyType, @@ -2362,7 +2672,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_fr.offset)) } - pub fn mesh_foot_bl( + fn mesh_foot_bl( &self, species: DSpecies, body_type: DBodyType, @@ -2383,7 +2693,7 @@ impl DragonLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_bl.offset)) } - pub fn mesh_foot_br( + fn mesh_foot_br( &self, species: DSpecies, body_type: DBodyType, @@ -2406,7 +2716,40 @@ impl DragonLateralSpec { } //// -pub fn mesh_bird_small_head( +make_vox_spec!( + bird_small::Body, + struct BirdSmallSpec {}, + |FigureKey { body, .. }, _spec, mut generate_mesh| { + [ + Some(mesh_bird_small_head(body.head, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_bird_small_torso(body.torso, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_bird_small_wing_l(body.wing_l, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_bird_small_wing_r(body.wing_r, |segment, offset| { + generate_mesh(segment, offset) + })), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); + +fn mesh_bird_small_head( head: bird_small::Head, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2419,7 +2762,7 @@ pub fn mesh_bird_small_head( ) } -pub fn mesh_bird_small_torso( +fn mesh_bird_small_torso( torso: bird_small::Torso, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2432,7 +2775,7 @@ pub fn mesh_bird_small_torso( ) } -pub fn mesh_bird_small_wing_l( +fn mesh_bird_small_wing_l( wing_l: bird_small::WingL, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2445,7 +2788,7 @@ pub fn mesh_bird_small_wing_l( ) } -pub fn mesh_bird_small_wing_r( +fn mesh_bird_small_wing_r( wing_r: bird_small::WingR, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2458,7 +2801,36 @@ pub fn mesh_bird_small_wing_r( ) } //// -pub fn mesh_fish_small_torso( +make_vox_spec!( + fish_small::Body, + struct FishSmallSpec {}, + |FigureKey { body, .. }, _spec, mut generate_mesh| { + [ + Some(mesh_fish_small_torso(body.torso, |segment, offset| { + generate_mesh(segment, offset) + })), + Some(mesh_fish_small_tail(body.tail, |segment, offset| { + generate_mesh(segment, offset) + })), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); + +fn mesh_fish_small_torso( torso: fish_small::Torso, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2471,7 +2843,7 @@ pub fn mesh_fish_small_torso( ) } -pub fn mesh_fish_small_tail( +fn mesh_fish_small_tail( tail: fish_small::Tail, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { @@ -2484,10 +2856,10 @@ pub fn mesh_fish_small_tail( ) } //// -#[derive(Serialize, Deserialize)] -pub struct BipedLargeCenterSpec(HashMap<(BLSpecies, BLBodyType), SidedBLCenterVoxSpec>); +#[derive(Deserialize)] +struct BipedLargeCenterSpec(HashMap<(BLSpecies, BLBodyType), SidedBLCenterVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedBLCenterVoxSpec { head: BipedLargeCenterSubSpec, jaw: BipedLargeCenterSubSpec, @@ -2497,16 +2869,16 @@ struct SidedBLCenterVoxSpec { main: BipedLargeCenterSubSpec, second: BipedLargeCenterSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct BipedLargeCenterSubSpec { offset: [f32; 3], // Should be relative to initial origin center: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct BipedLargeLateralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLLateralVoxSpec>); +#[derive(Deserialize)] +struct BipedLargeLateralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedBLLateralVoxSpec { shoulder_l: BipedLargeLateralSubSpec, shoulder_r: BipedLargeLateralSubSpec, @@ -2517,35 +2889,102 @@ struct SidedBLLateralVoxSpec { foot_l: BipedLargeLateralSubSpec, foot_r: BipedLargeLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct BipedLargeLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for BipedLargeCenterSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for BipedLargeLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + biped_large::Body, + struct BipedLargeSpec { + center: BipedLargeCenterSpec = "voxygen.voxel.biped_large_center_manifest", + lateral: BipedLargeLateralSpec = "voxygen.voxel.biped_large_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.center.asset.mesh_head( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_jaw( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_torso_upper( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_torso_lower( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_tail( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_main( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_second( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_shoulder_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_shoulder_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_hand_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_hand_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + ] + }, +); impl BipedLargeCenterSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.biped_large_center_manifest", indicator) - .unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, species: BLSpecies, body_type: BLBodyType, @@ -2566,7 +3005,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.head.offset)) } - pub fn mesh_jaw( + fn mesh_jaw( &self, species: BLSpecies, body_type: BLBodyType, @@ -2587,7 +3026,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.jaw.offset)) } - pub fn mesh_torso_upper( + fn mesh_torso_upper( &self, species: BLSpecies, body_type: BLBodyType, @@ -2608,7 +3047,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.torso_upper.offset)) } - pub fn mesh_torso_lower( + fn mesh_torso_lower( &self, species: BLSpecies, body_type: BLBodyType, @@ -2629,7 +3068,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.torso_lower.offset)) } - pub fn mesh_tail( + fn mesh_tail( &self, species: BLSpecies, body_type: BLBodyType, @@ -2650,7 +3089,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.tail.offset)) } - pub fn mesh_main( + fn mesh_main( &self, species: BLSpecies, body_type: BLBodyType, @@ -2671,7 +3110,7 @@ impl BipedLargeCenterSpec { generate_mesh(center, Vec3::from(spec.main.offset)) } - pub fn mesh_second( + fn mesh_second( &self, species: BLSpecies, body_type: BLBodyType, @@ -2693,12 +3132,7 @@ impl BipedLargeCenterSpec { } } impl BipedLargeLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.biped_large_lateral_manifest", indicator) - .unwrap() - } - - pub fn mesh_shoulder_l( + fn mesh_shoulder_l( &self, species: BLSpecies, body_type: BLBodyType, @@ -2719,7 +3153,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.shoulder_l.offset)) } - pub fn mesh_shoulder_r( + fn mesh_shoulder_r( &self, species: BLSpecies, body_type: BLBodyType, @@ -2740,7 +3174,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.shoulder_r.offset)) } - pub fn mesh_hand_l( + fn mesh_hand_l( &self, species: BLSpecies, body_type: BLBodyType, @@ -2761,7 +3195,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.hand_l.offset)) } - pub fn mesh_hand_r( + fn mesh_hand_r( &self, species: BLSpecies, body_type: BLBodyType, @@ -2782,7 +3216,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.hand_r.offset)) } - pub fn mesh_leg_l( + fn mesh_leg_l( &self, species: BLSpecies, body_type: BLBodyType, @@ -2803,7 +3237,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_l.offset)) } - pub fn mesh_leg_r( + fn mesh_leg_r( &self, species: BLSpecies, body_type: BLBodyType, @@ -2824,7 +3258,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_r.offset)) } - pub fn mesh_foot_l( + fn mesh_foot_l( &self, species: BLSpecies, body_type: BLBodyType, @@ -2845,7 +3279,7 @@ impl BipedLargeLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_l.offset)) } - pub fn mesh_foot_r( + fn mesh_foot_r( &self, species: BLSpecies, body_type: BLBodyType, @@ -2867,24 +3301,24 @@ impl BipedLargeLateralSpec { } } //// -#[derive(Serialize, Deserialize)] -pub struct GolemCenterSpec(HashMap<(GSpecies, GBodyType), SidedGCenterVoxSpec>); +#[derive(Deserialize)] +struct GolemCenterSpec(HashMap<(GSpecies, GBodyType), SidedGCenterVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedGCenterVoxSpec { head: GolemCenterSubSpec, torso_upper: GolemCenterSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct GolemCenterSubSpec { offset: [f32; 3], // Should be relative to initial origin center: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct GolemLateralSpec(HashMap<(GSpecies, GBodyType), SidedGLateralVoxSpec>); +#[derive(Deserialize)] +struct GolemLateralSpec(HashMap<(GSpecies, GBodyType), SidedGLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedGLateralVoxSpec { shoulder_l: GolemLateralSubSpec, shoulder_r: GolemLateralSubSpec, @@ -2895,34 +3329,82 @@ struct SidedGLateralVoxSpec { foot_l: GolemLateralSubSpec, foot_r: GolemLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct GolemLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for GolemCenterSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for GolemLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + golem::Body, + struct GolemSpec { + center: GolemCenterSpec = "voxygen.voxel.golem_center_manifest", + lateral: GolemLateralSpec = "voxygen.voxel.golem_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.center.asset.mesh_head( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.center.asset.mesh_torso_upper( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_shoulder_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_shoulder_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_hand_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_hand_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_leg_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_l( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_r( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + None, + None, + None, + None, + None, + ] + }, +); impl GolemCenterSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.golem_center_manifest", indicator).unwrap() - } - - pub fn mesh_head( + fn mesh_head( &self, species: GSpecies, body_type: GBodyType, @@ -2943,7 +3425,7 @@ impl GolemCenterSpec { generate_mesh(center, Vec3::from(spec.head.offset)) } - pub fn mesh_torso_upper( + fn mesh_torso_upper( &self, species: GSpecies, body_type: GBodyType, @@ -2965,11 +3447,7 @@ impl GolemCenterSpec { } } impl GolemLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.golem_lateral_manifest", indicator).unwrap() - } - - pub fn mesh_shoulder_l( + fn mesh_shoulder_l( &self, species: GSpecies, body_type: GBodyType, @@ -2990,7 +3468,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.shoulder_l.offset)) } - pub fn mesh_shoulder_r( + fn mesh_shoulder_r( &self, species: GSpecies, body_type: GBodyType, @@ -3011,7 +3489,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.shoulder_r.offset)) } - pub fn mesh_hand_l( + fn mesh_hand_l( &self, species: GSpecies, body_type: GBodyType, @@ -3032,7 +3510,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.hand_l.offset)) } - pub fn mesh_hand_r( + fn mesh_hand_r( &self, species: GSpecies, body_type: GBodyType, @@ -3053,7 +3531,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.hand_r.offset)) } - pub fn mesh_leg_l( + fn mesh_leg_l( &self, species: GSpecies, body_type: GBodyType, @@ -3074,7 +3552,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_l.offset)) } - pub fn mesh_leg_r( + fn mesh_leg_r( &self, species: GSpecies, body_type: GBodyType, @@ -3095,7 +3573,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.leg_r.offset)) } - pub fn mesh_foot_l( + fn mesh_foot_l( &self, species: GSpecies, body_type: GBodyType, @@ -3116,7 +3594,7 @@ impl GolemLateralSpec { generate_mesh(lateral, Vec3::from(spec.foot_l.offset)) } - pub fn mesh_foot_r( + fn mesh_foot_r( &self, species: GSpecies, body_type: GBodyType, @@ -3138,12 +3616,12 @@ impl GolemLateralSpec { } } -/// +///// -#[derive(Serialize, Deserialize)] -pub struct QuadrupedLowCentralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLCentralVoxSpec>); +#[derive(Deserialize)] +struct QuadrupedLowCentralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLCentralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct SidedQLCentralVoxSpec { upper: QuadrupedLowCentralSubSpec, lower: QuadrupedLowCentralSubSpec, @@ -3152,50 +3630,97 @@ struct SidedQLCentralVoxSpec { tail_front: QuadrupedLowCentralSubSpec, tail_rear: QuadrupedLowCentralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedLowCentralSubSpec { offset: [f32; 3], // Should be relative to initial origin central: VoxSimple, } -#[derive(Serialize, Deserialize)] -pub struct QuadrupedLowLateralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLLateralVoxSpec>); -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] +struct QuadrupedLowLateralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLLateralVoxSpec>); +#[derive(Deserialize)] struct SidedQLLateralVoxSpec { front_left: QuadrupedLowLateralSubSpec, front_right: QuadrupedLowLateralSubSpec, back_left: QuadrupedLowLateralSubSpec, back_right: QuadrupedLowLateralSubSpec, } -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] struct QuadrupedLowLateralSubSpec { offset: [f32; 3], // Should be relative to initial origin lateral: VoxSimple, } -impl Asset for QuadrupedLowCentralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - -impl Asset for QuadrupedLowLateralSpec { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} +make_vox_spec!( + quadruped_low::Body, + struct QuadrupedLowSpec { + central: QuadrupedLowCentralSpec = "voxygen.voxel.quadruped_low_central_manifest", + lateral: QuadrupedLowLateralSpec = "voxygen.voxel.quadruped_low_lateral_manifest", + }, + |FigureKey { body, .. }, spec, mut generate_mesh| { + [ + Some(spec.central.asset.mesh_head_upper( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_head_lower( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_jaw( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_chest( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_tail_front( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.central.asset.mesh_tail_rear( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_fr( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_bl( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + Some(spec.lateral.asset.mesh_foot_br( + body.species, + body.body_type, + |segment, offset| generate_mesh(segment, offset), + )), + None, + None, + None, + None, + None, + None, + ] + }, +); impl QuadrupedLowCentralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_low_central_manifest", indicator) - .unwrap() - } - - pub fn mesh_head_upper( + fn mesh_head_upper( &self, species: QLSpecies, body_type: QLBodyType, @@ -3216,7 +3741,7 @@ impl QuadrupedLowCentralSpec { generate_mesh(central, Vec3::from(spec.upper.offset)) } - pub fn mesh_head_lower( + fn mesh_head_lower( &self, species: QLSpecies, body_type: QLBodyType, @@ -3237,7 +3762,7 @@ impl QuadrupedLowCentralSpec { generate_mesh(central, Vec3::from(spec.lower.offset)) } - pub fn mesh_jaw( + fn mesh_jaw( &self, species: QLSpecies, body_type: QLBodyType, @@ -3258,7 +3783,7 @@ impl QuadrupedLowCentralSpec { generate_mesh(central, Vec3::from(spec.jaw.offset)) } - pub fn mesh_chest( + fn mesh_chest( &self, species: QLSpecies, body_type: QLBodyType, @@ -3279,7 +3804,7 @@ impl QuadrupedLowCentralSpec { generate_mesh(central, Vec3::from(spec.chest.offset)) } - pub fn mesh_tail_rear( + fn mesh_tail_rear( &self, species: QLSpecies, body_type: QLBodyType, @@ -3300,7 +3825,7 @@ impl QuadrupedLowCentralSpec { generate_mesh(central, Vec3::from(spec.tail_rear.offset)) } - pub fn mesh_tail_front( + fn mesh_tail_front( &self, species: QLSpecies, body_type: QLBodyType, @@ -3323,12 +3848,7 @@ impl QuadrupedLowCentralSpec { } impl QuadrupedLowLateralSpec { - pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { - assets::load_watched::("voxygen.voxel.quadruped_low_lateral_manifest", indicator) - .unwrap() - } - - pub fn mesh_foot_fl( + fn mesh_foot_fl( &self, species: QLSpecies, body_type: QLBodyType, @@ -3349,7 +3869,7 @@ impl QuadrupedLowLateralSpec { generate_mesh(lateral, Vec3::from(spec.front_left.offset)) } - pub fn mesh_foot_fr( + fn mesh_foot_fr( &self, species: QLSpecies, body_type: QLBodyType, @@ -3370,7 +3890,7 @@ impl QuadrupedLowLateralSpec { generate_mesh(lateral, Vec3::from(spec.front_right.offset)) } - pub fn mesh_foot_bl( + fn mesh_foot_bl( &self, species: QLSpecies, body_type: QLBodyType, @@ -3391,7 +3911,7 @@ impl QuadrupedLowLateralSpec { generate_mesh(lateral, Vec3::from(spec.back_left.offset)) } - pub fn mesh_foot_br( + fn mesh_foot_br( &self, species: QLSpecies, body_type: QLBodyType, @@ -3413,9 +3933,33 @@ impl QuadrupedLowLateralSpec { } } -/// +//// +make_vox_spec!( + object::Body, + struct ObjectSpec {}, + |FigureKey { body, .. }, _spec, generate_mesh| { + [ + Some(mesh_object(body, generate_mesh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ] + }, +); -pub fn mesh_object( +fn mesh_object( obj: &object::Body, generate_mesh: impl FnOnce(Segment, Vec3) -> BoneMeshes, ) -> BoneMeshes { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index f45f660c61..25d033ac6e 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -6,10 +6,9 @@ pub use load::load_mesh; // TODO: Don't make this public. use crate::{ ecs::comp::Interpolated, - mesh::greedy::GreedyMesh, render::{ - ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel, Mesh, - RenderError, Renderer, ShadowPipeline, TerrainPipeline, Texture, + ColLightFmt, ColLightInfo, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel, + Mesh, RenderError, Renderer, ShadowPipeline, TerrainPipeline, Texture, }, scene::{ camera::{Camera, CameraMode, Dependents}, @@ -308,6 +307,7 @@ pub struct FigureMgr { fish_medium_model_cache: FigureModelCache, fish_small_model_cache: FigureModelCache, biped_large_model_cache: FigureModelCache, + object_model_cache: FigureModelCache, golem_model_cache: FigureModelCache, states: FigureMgrStates, } @@ -327,6 +327,7 @@ impl FigureMgr { fish_medium_model_cache: FigureModelCache::new(), fish_small_model_cache: FigureModelCache::new(), biped_large_model_cache: FigureModelCache::new(), + object_model_cache: FigureModelCache::new(), golem_model_cache: FigureModelCache::new(), states: FigureMgrStates::default(), } @@ -354,6 +355,7 @@ impl FigureMgr { .clean(&mut self.col_lights, tick); self.biped_large_model_cache .clean(&mut self.col_lights, tick); + self.object_model_cache.clean(&mut self.col_lights, tick); self.golem_model_cache.clean(&mut self.col_lights, tick); } @@ -685,7 +687,7 @@ impl FigureMgr { }; match body { - Body::Humanoid(_) => { + Body::Humanoid(body) => { let (model, skeleton_attr) = self.model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -694,6 +696,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1046,7 +1049,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1054,7 +1057,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::QuadrupedSmall(_) => { + Body::QuadrupedSmall(body) => { let (model, skeleton_attr) = self.quadruped_small_model_cache.get_or_create_model( renderer, @@ -1064,6 +1067,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1147,7 +1151,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1155,7 +1159,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::QuadrupedMedium(_) => { + Body::QuadrupedMedium(body) => { let (model, skeleton_attr) = self.quadruped_medium_model_cache.get_or_create_model( renderer, @@ -1165,6 +1169,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1248,7 +1253,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1256,7 +1261,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::QuadrupedLow(_) => { + Body::QuadrupedLow(body) => { let (model, skeleton_attr) = self.quadruped_low_model_cache.get_or_create_model( renderer, @@ -1266,6 +1271,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1347,7 +1353,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1355,7 +1361,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::BirdMedium(_) => { + Body::BirdMedium(body) => { let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1364,6 +1370,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1443,7 +1450,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1451,7 +1458,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::FishMedium(_) => { + Body::FishMedium(body) => { let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1460,6 +1467,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1528,7 +1536,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1536,7 +1544,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::Dragon(_) => { + Body::Dragon(body) => { let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1545,6 +1553,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = @@ -1609,7 +1618,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1617,7 +1626,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::Critter(_) => { + Body::Critter(body) => { let (model, skeleton_attr) = self.critter_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1626,6 +1635,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = @@ -1691,7 +1701,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1699,7 +1709,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::BirdSmall(_) => { + Body::BirdSmall(body) => { let (model, skeleton_attr) = self.bird_small_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1708,6 +1718,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1776,7 +1787,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1784,7 +1795,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::FishSmall(_) => { + Body::FishSmall(body) => { let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1793,6 +1804,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1861,7 +1873,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1869,7 +1881,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::BipedLarge(_) => { + Body::BipedLarge(body) => { let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1878,6 +1890,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = self @@ -1966,7 +1979,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -1974,7 +1987,7 @@ impl FigureMgr { &mut update_buf, ); }, - Body::Golem(_) => { + Body::Golem(body) => { let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model( renderer, &mut self.col_lights, @@ -1983,6 +1996,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = @@ -2048,7 +2062,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, in_frustum, is_player, @@ -2056,8 +2070,8 @@ impl FigureMgr { &mut update_buf, ); }, - Body::Object(_) => { - let (model, _) = &self.model_cache.get_or_create_model( + Body::Object(body) => { + let (model, _) = self.object_model_cache.get_or_create_model( renderer, &mut self.col_lights, *body, @@ -2065,6 +2079,7 @@ impl FigureMgr { tick, player_camera_mode, player_character_state, + scene_data.thread_pool, ); let state = @@ -2080,7 +2095,7 @@ impl FigureMgr { col, dt, state_animation_rate, - &model, + model, lpindex, true, is_player, @@ -2102,7 +2117,7 @@ impl FigureMgr { } pub fn render_shadows( - &mut self, + &self, renderer: &mut Renderer, state: &State, tick: u64, @@ -2127,7 +2142,6 @@ impl FigureMgr { .filter(|(_, _, _, _, stats, _, _)| stats.map_or(true, |s| !s.is_dead)) .for_each(|(entity, pos, _, body, _, loadout, _)| { if let Some((locals, bone_consts, model, _)) = self.get_model_for_render( - renderer, tick, camera, None, @@ -2153,7 +2167,7 @@ impl FigureMgr { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 pub fn render( - &mut self, + &self, renderer: &mut Renderer, state: &State, player_entity: EcsEntity, @@ -2184,7 +2198,6 @@ impl FigureMgr { if !is_player { if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( - renderer, tick, camera, character_state, @@ -2204,7 +2217,7 @@ impl FigureMgr { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 pub fn render_player( - &mut self, + &self, renderer: &mut Renderer, state: &State, player_entity: EcsEntity, @@ -2233,7 +2246,6 @@ impl FigureMgr { let loadout = loadout_storage.get(player_entity); if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( - renderer, tick, camera, character_state, @@ -2260,8 +2272,7 @@ impl FigureMgr { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 fn get_model_for_render( - &mut self, - renderer: &mut Renderer, + &self, tick: u64, camera: &Camera, character_state: Option<&CharacterState>, @@ -2283,7 +2294,7 @@ impl FigureMgr { let character_state = if is_player { character_state } else { None }; let FigureMgr { - col_lights: ref mut col_lights_, + col_lights: ref col_lights_, model_cache, critter_model_cache, quadruped_small_model_cache, @@ -2295,6 +2306,7 @@ impl FigureMgr { fish_medium_model_cache, fish_small_model_cache, biped_large_model_cache, + object_model_cache, golem_model_cache, states: FigureMgrStates { @@ -2313,269 +2325,232 @@ impl FigureMgr { object_states, }, } = self; - let col_lights = &mut *col_lights_; + let col_lights = &*col_lights_; if let Some((locals, bone_consts, model_entry)) = match body { - Body::Humanoid(_) => character_states + Body::Humanoid(body) => character_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::QuadrupedSmall(_) => quadruped_small_states + Body::QuadrupedSmall(body) => quadruped_small_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &quadruped_small_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + quadruped_small_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::QuadrupedMedium(_) => quadruped_medium_states + Body::QuadrupedMedium(body) => quadruped_medium_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &quadruped_medium_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + quadruped_medium_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::QuadrupedLow(_) => quadruped_low_states + Body::QuadrupedLow(body) => quadruped_low_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &quadruped_low_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + quadruped_low_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::BirdMedium(_) => bird_medium_states + Body::BirdMedium(body) => bird_medium_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &bird_medium_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + bird_medium_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::FishMedium(_) => fish_medium_states + Body::FishMedium(body) => fish_medium_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &fish_medium_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + fish_medium_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::Critter(_) => critter_states + Body::Critter(body) => critter_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &critter_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + critter_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::Dragon(_) => dragon_states + Body::Dragon(body) => dragon_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &dragon_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + dragon_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::BirdSmall(_) => bird_small_states + Body::BirdSmall(body) => bird_small_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &bird_small_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + bird_small_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::FishSmall(_) => fish_small_states + Body::FishSmall(body) => fish_small_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &fish_small_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + fish_small_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::BipedLarge(_) => biped_large_states + Body::BipedLarge(body) => biped_large_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &biped_large_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + biped_large_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::Golem(_) => golem_states + Body::Golem(body) => golem_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &golem_model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + golem_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), - Body::Object(_) => object_states + Body::Object(body) => object_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( state.locals(), state.bone_consts(), - &model_cache - .get_or_create_model( - renderer, - col_lights, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, + object_model_cache.get_model( + col_lights, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ), ) }), } { + let model_entry = model_entry?; + let figure_low_detail_distance = figure_lod_render_distance * 0.75; let figure_mid_detail_distance = figure_lod_render_distance * 0.5; @@ -2627,14 +2602,13 @@ impl FigureColLights { /// NOTE: Panics if the vertex range bounds are not in range of the opaque /// model stored in the BoneMeshes parameter. This is part of the /// function contract. - pub fn create_figure<'a, const N: usize>( + pub fn create_figure( &mut self, renderer: &mut Renderer, - greedy: GreedyMesh<'a>, + (tex, tex_size): ColLightInfo, (opaque, bounds): (Mesh, math::Aabb), vertex_range: [Range; N], ) -> Result, RenderError> { - let (tex, tex_size) = greedy.finalize(); let atlas = &mut self.atlas; let allocation = atlas .allocate(guillotiere::Size::new( @@ -2771,14 +2745,31 @@ impl FigureState { col: vek::Rgba, dt: f32, state_animation_rate: f32, - model: &FigureModelEntry, + model: Option<&FigureModelEntry>, _lpindex: u8, _visible: bool, is_player: bool, - camera: &Camera, + _camera: &Camera, buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT], ) { - let _frustum = camera.frustum(); + // NOTE: As long as update() always gets called after get_or_create_model(), and + // visibility is not set again until after the model is rendered, we + // know we don't pair the character model with invalid model state. + // + // Currently, the only exception to this during normal gameplay is in the very + // first tick after a model is created (so there's no `last_character` + // state). So in theory, we could have incorrect model data during this + // tick. It is possible to resolve this in a few ways, but since + // currently we don't actually use the model state for anything, we + // currently ignore this potential issue. + // + // FIXME: Address the above at some point. + let model = if let Some(model) = model { + model + } else { + self.visible = false; + return; + }; // Approximate as a sphere with radius equal to the // largest dimension (if we were exact, it should just be half the largest diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 362cfdd0c4..ead5aeadc7 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -7,7 +7,7 @@ use crate::{ }, }; use common::{ - assets, + assets::Asset, comp::{item::Reagent, object, Body, CharacterState, Pos}, figure::Segment, outcome::Outcome, @@ -369,7 +369,7 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model(DEFAULT_MODEL_KEY); + let vox = DotVoxData::load_expect(DEFAULT_MODEL_KEY); // NOTE: If we add texturing we may eventually try to share it among all // particles in a single atlas. diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 785b8a6784..72a1b63ab7 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -19,7 +19,7 @@ use anim::{ }; use client::Client; use common::{ - comp::{humanoid, item::ItemKind, Body, Loadout}, + comp::{humanoid, item::ItemKind, Loadout}, figure::Segment, terrain::BlockKind, vol::{BaseVol, ReadVol, Vox}, @@ -87,10 +87,11 @@ pub struct Scene { char_ori: f32, } -pub struct SceneData { +pub struct SceneData<'a> { pub time: f64, pub delta_time: f32, pub tick: u64, + pub thread_pool: &'a uvth::ThreadPool, pub body: Option, pub gamma: f32, pub figure_lod_render_distance: f32, @@ -164,7 +165,7 @@ impl Scene { // 2^27, which fits in a u32. let range = range.start as u32..range.end as u32; let model = col_lights - .create_figure(renderer, greedy, (opaque_mesh, bounds), [range]) + .create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]) .unwrap(); let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; state.update( @@ -175,7 +176,7 @@ impl Scene { Rgba::broadcast(1.0), 15.0, // Want to get there immediately. 1.0, - &model, + Some(&model), 0, true, false, @@ -304,16 +305,17 @@ impl Scene { *self.figure_state.skeleton_mut() = anim::vek::Lerp::lerp(&*self.figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp); - let model = &self + let model = self .figure_model_cache .get_or_create_model( renderer, &mut self.col_lights, - Body::Humanoid(body), + body, loadout, scene_data.tick, CameraMode::default(), None, + scene_data.thread_pool, ) .0; let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; @@ -325,7 +327,7 @@ impl Scene { Rgba::broadcast(1.0), scene_data.delta_time, 1.0, - &model, + model, 0, true, false, @@ -350,27 +352,25 @@ impl Scene { ); if let Some(body) = body { - let model = &self - .figure_model_cache - .get_or_create_model( - renderer, - &mut self.col_lights, - Body::Humanoid(body), - loadout, - tick, - CameraMode::default(), - None, - ) - .0; - - renderer.render_figure( - &model.models[0], - &self.col_lights.texture(model), - &self.data, - self.figure_state.locals(), - self.figure_state.bone_consts(), - &self.lod, + let model = &self.figure_model_cache.get_model( + &self.col_lights, + body, + loadout, + tick, + CameraMode::default(), + None, ); + + if let Some(model) = model { + renderer.render_figure( + &model.models[0], + &self.col_lights.texture(model), + &self.data, + self.figure_state.locals(), + self.figure_state.bone_consts(), + &self.lod, + ); + } } if let Some((model, state)) = &self.backdrop { diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index a148b34d6c..35359a6d4d 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -13,7 +13,7 @@ use crate::{ use super::{math, LodData, SceneData}; use common::{ - assets, + assets::Asset, figure::Segment, spiral::Spiral2d, terrain::{Block, BlockKind, TerrainChunk}, @@ -25,6 +25,7 @@ use crossbeam::channel; use dot_vox::DotVoxData; use guillotiere::AtlasAllocator; use hashbrown::HashMap; +use image::DynamicImage; use std::sync::Arc; use tracing::warn; use treeculler::{BVol, Frustum, AABB}; @@ -525,7 +526,7 @@ impl Terrain { // NOTE: Tracks the start vertex of the next model to be meshed. let mut make_models = |(kind, variation), s, offset, lod_axes: Vec3| { let scaled = [1.0, 0.8, 0.6, 0.4, 0.2]; - let model = assets::load_expect::(s); + let model = DotVoxData::load_expect(s); let zero = Vec3::zero(); let model_size = model .models @@ -2401,7 +2402,7 @@ impl Terrain { sprite_col_lights, waves: renderer .create_texture( - &assets::load_expect("voxygen.texture.waves"), + &DynamicImage::load_expect("voxygen.texture.waves"), Some(gfx::texture::FilterMethod::Trilinear), Some(gfx::texture::WrapMode::Tile), None, diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index a66f73ede5..f6bafd4804 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -13,7 +13,7 @@ use crate::{ }; use client::{self, Client}; use common::{ - assets::{load_expect, load_watched}, + assets::Asset, comp, comp::{ ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR, @@ -72,7 +72,7 @@ impl SessionState { .camera_mut() .set_fov_deg(global_state.settings.graphics.fov); let hud = Hud::new(global_state, &client.borrow()); - let voxygen_i18n = load_expect::(&i18n_asset_key( + let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); @@ -196,7 +196,7 @@ impl PlayState for SessionState { fn tick(&mut self, global_state: &mut GlobalState, events: Vec) -> PlayStateResult { // NOTE: Not strictly necessary, but useful for hotloading translation changes. - self.voxygen_i18n = load_expect::(&i18n_asset_key( + self.voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key( &global_state.settings.language.selected_language, )); @@ -991,7 +991,7 @@ impl PlayState for SessionState { HudEvent::ChangeLanguage(new_language) => { global_state.settings.language.selected_language = new_language.language_identifier; - self.voxygen_i18n = load_watched::( + self.voxygen_i18n = VoxygenLocalization::load_watched( &i18n_asset_key(&global_state.settings.language.selected_language), &mut global_state.localization_watcher, ) diff --git a/voxygen/src/ui/fonts.rs b/voxygen/src/ui/fonts.rs index b1f5924249..9c726eadba 100644 --- a/voxygen/src/ui/fonts.rs +++ b/voxygen/src/ui/fonts.rs @@ -1,4 +1,5 @@ use crate::i18n::{Font, VoxygenFonts}; +use common::assets::Asset; pub struct ConrodVoxygenFont { metadata: Font, @@ -10,7 +11,7 @@ impl ConrodVoxygenFont { pub fn new(font: &Font, ui: &mut crate::ui::Ui) -> ConrodVoxygenFont { return Self { metadata: font.clone(), - conrod_id: ui.new_font(common::assets::load_expect(&font.asset_key)), + conrod_id: ui.new_font(crate::ui::Font::load_expect(&font.asset_key)), }; } diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index 7eb011136b..cf828a0502 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -1,6 +1,6 @@ use super::{Graphic, SampleStrat, Transform}; use common::{ - assets::{load, Error}, + assets::{Asset, Error}, figure::Segment, }; use dot_vox::DotVoxData; @@ -24,7 +24,7 @@ impl<'a> GraphicCreator<'a> for ImageGraphic { type Specifier = &'a str; fn new_graphic(specifier: Self::Specifier) -> Result { - Ok(Graphic::Image(load::(specifier)?, None)) + Ok(Graphic::Image(DynamicImage::load(specifier)?, None)) } } @@ -37,7 +37,7 @@ pub enum VoxelSs9Graphic {} pub enum VoxelPixArtGraphic {} fn load_segment(specifier: &str) -> Result, Error> { - let dot_vox = load::(specifier)?; + let dot_vox = DotVoxData::load(specifier)?; let seg = dot_vox.as_ref().into(); Ok(Arc::new(seg)) } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 8490719cf7..fe668ff040 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -13,10 +13,10 @@ use common::{ vol::{ReadVol, Vox}, }; use core::ops::{Div, Mul, Range}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub pyramid: (u8, u8, u8), // TODO(@Sharp): After the merge, construct enough infrastructure to make it convenient to diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index aa1bf46225..3fdbda950b 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -13,7 +13,7 @@ use common::{ vol::RectVolSize, }; use noise::NoiseFn; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::{ cmp::Reverse, f32, f64, @@ -26,7 +26,7 @@ pub struct ColumnGen<'a> { pub sim: &'a WorldSim, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub cold_grass: (f32, f32, f32), pub warm_grass: (f32, f32, f32), diff --git a/world/src/index.rs b/world/src/index.rs index d8dedd23ed..5ad7b88721 100644 --- a/world/src/index.rs +++ b/world/src/index.rs @@ -1,6 +1,6 @@ use crate::{site::Site, Colors}; use common::{ - assets::{self, watch::ReloadIndicator}, + assets::{watch::ReloadIndicator, Asset, Ron}, store::Store, }; use core::ops::Deref; @@ -53,7 +53,7 @@ impl Index { /// NOTE: Panics if the color manifest cannot be loaded. pub fn new(seed: u32) -> (Self, Arc) { let mut indicator = ReloadIndicator::new(); - let colors = assets::load_watched::(WORLD_COLORS_MANIFEST, &mut indicator) + let colors = Ron::::load_watched(WORLD_COLORS_MANIFEST, &mut indicator) .expect("Could not load world colors!"); ( @@ -90,7 +90,7 @@ impl IndexOwned { ) -> Option { self.indicator.reloaded().then(move || { // We know the asset was loaded before, so load_expect should be fine. - self.colors = assets::load_expect::(WORLD_COLORS_MANIFEST); + self.colors = Ron::::load_expect(WORLD_COLORS_MANIFEST); reload(self) }) } diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 14d1e69469..6ca20116b2 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -5,7 +5,8 @@ use crate::{ IndexRef, CONFIG, }; use common::{ - assets, comp, + assets::Asset, + comp, generation::{ChunkSupplement, EntityInfo}, lottery::Lottery, terrain::{Block, BlockKind}, @@ -13,14 +14,14 @@ use common::{ }; use noise::NoiseFn; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::{ f32, ops::{Mul, Sub}, }; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub bridge: (u8, u8, u8), pub stalagtite: (u8, u8, u8), @@ -505,7 +506,7 @@ pub fn apply_caves_to<'a>( if RandomField::new(index.seed).chance(wpos2d.into(), 0.001 * difficulty.powf(1.5)) && cave_base < surface_z as i32 - 25 { - let kind = *assets::load_expect::>("common.cave_scatter") + let kind = *Lottery::::load_expect("common.cave_scatter") .choose_seeded(RandomField::new(index.seed + 1).get(wpos2d.into())); let _ = vol.set( Vec3::new(offs.x, offs.y, cave_base), diff --git a/world/src/lib.rs b/world/src/lib.rs index 80670bbd64..fd3b887092 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -34,7 +34,6 @@ use crate::{ util::{Grid, Sampler}, }; use common::{ - assets::{self, Asset}, comp::{self, bird_medium, critter, quadruped_low, quadruped_medium, quadruped_small}, generation::{ChunkSupplement, EntityInfo}, msg::server::WorldMapMsg, @@ -42,8 +41,8 @@ use common::{ vol::{ReadVol, RectVolSize, Vox, WriteVol}, }; use rand::Rng; -use serde::{Deserialize, Serialize}; -use std::{fs::File, io::BufReader, time::Duration}; +use serde::Deserialize; +use std::time::Duration; use vek::*; #[derive(Debug)] @@ -56,7 +55,7 @@ pub struct World { civs: civ::Civs, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub deep_stone_color: (u8, u8, u8), pub block: block::Colors, @@ -65,14 +64,6 @@ pub struct Colors { pub site: site::Colors, } -impl Asset for Colors { - const ENDINGS: &'static [&'static str] = &["ron"]; - - fn parse(buf_reader: BufReader) -> Result { - ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) - } -} - impl World { pub fn generate(seed: u32, opts: sim::WorldOpts) -> (Self, IndexOwned) { // NOTE: Generating index first in order to quickly fail if the color manifest diff --git a/world/src/site/castle/mod.rs b/world/src/site/castle/mod.rs index ab5b15e638..aba6553f33 100644 --- a/world/src/site/castle/mod.rs +++ b/world/src/site/castle/mod.rs @@ -15,7 +15,7 @@ use common::{ }; use core::f32; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; struct Keep { @@ -49,7 +49,7 @@ pub struct GenCtx<'a, R: Rng> { rng: &'a mut R, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors; impl Castle { diff --git a/world/src/site/dungeon/mod.rs b/world/src/site/dungeon/mod.rs index 5ec09e375e..8de698a754 100644 --- a/world/src/site/dungeon/mod.rs +++ b/world/src/site/dungeon/mod.rs @@ -8,9 +8,9 @@ use crate::{ IndexRef, }; use common::{ - assets, + assets::Asset, astar::Astar, - comp, + comp::{self, item::ItemAsset}, generation::{ChunkSupplement, EntityInfo}, lottery::Lottery, npc, @@ -22,7 +22,7 @@ use core::{f32, hash::BuildHasherDefault}; use fxhash::FxHasher64; use lazy_static::lazy_static; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::sync::Arc; use vek::*; @@ -40,7 +40,7 @@ pub struct GenCtx<'a, R: Rng> { rng: &'a mut R, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub stone: (u8, u8, u8), } @@ -461,12 +461,11 @@ impl Floor { && !tile_is_pillar { // Bad - let chosen = - assets::load_expect::>(match rng.gen_range(0, 5) { - 0 => "common.loot_tables.loot_table_humanoids", - 1 => "common.loot_tables.loot_table_armor_misc", - _ => "common.loot_tables.loot_table_cultists", - }); + let chosen = Lottery::::load_expect(match rng.gen_range(0, 5) { + 0 => "common.loot_tables.loot_table_humanoids", + 1 => "common.loot_tables.loot_table_armor_misc", + _ => "common.loot_tables.loot_table_cultists", + }); let chosen = chosen.choose(); let entity = EntityInfo::at( tile_wcenter.map(|e| e as f32) @@ -479,8 +478,8 @@ impl Floor { .with_alignment(comp::Alignment::Enemy) .with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_automatic_name() - .with_loot_drop(assets::load_expect_cloned(chosen)) - .with_main_tool(assets::load_expect_cloned(match rng.gen_range(0, 6) { + .with_loot_drop(ItemAsset::load_expect_cloned(chosen)) + .with_main_tool(ItemAsset::load_expect_cloned(match rng.gen_range(0, 6) { 0 => "common.items.npc_weapons.axe.malachite_axe-0", 1 => "common.items.npc_weapons.sword.cultist_purp_2h-0", 2 => "common.items.npc_weapons.sword.cultist_purp_2h-0", @@ -507,7 +506,7 @@ impl Floor { boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 }; if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d { - let chosen = assets::load_expect::>( + let chosen = Lottery::::load_expect( "common.loot_tables.loot_table_boss_cultist-leader", ); let chosen = chosen.choose(); @@ -520,7 +519,7 @@ impl Floor { "Cult Leader {}", npc::get_npc_name(npc::NpcKind::Humanoid) )) - .with_main_tool(assets::load_expect_cloned( + .with_main_tool(ItemAsset::load_expect_cloned( match rng.gen_range(0, 1) { //Add more possible cult leader npc_weapons here _ => { @@ -528,7 +527,7 @@ impl Floor { }, }, )) - .with_loot_drop(assets::load_expect_cloned(chosen)); + .with_loot_drop(ItemAsset::load_expect_cloned(chosen)); supplement.add_entity(entity); } diff --git a/world/src/site/mod.rs b/world/src/site/mod.rs index 01f9985f4d..a107b37909 100644 --- a/world/src/site/mod.rs +++ b/world/src/site/mod.rs @@ -17,10 +17,10 @@ use common::{ vol::{BaseVol, ReadVol, RectSizedVol, WriteVol}, }; use rand::Rng; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub castle: castle::Colors, pub dungeon: dungeon::Colors, diff --git a/world/src/site/settlement/building/archetype/house.rs b/world/src/site/settlement/building/archetype/house.rs index daecf45a11..182c7043d9 100644 --- a/world/src/site/settlement/building/archetype/house.rs +++ b/world/src/site/settlement/building/archetype/house.rs @@ -12,10 +12,10 @@ use common::{ vol::Vox, }; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub foundation: (u8, u8, u8), pub floor: (u8, u8, u8), diff --git a/world/src/site/settlement/building/archetype/keep.rs b/world/src/site/settlement/building/archetype/keep.rs index 160772f6e4..836c74030d 100644 --- a/world/src/site/settlement/building/archetype/keep.rs +++ b/world/src/site/settlement/building/archetype/keep.rs @@ -10,10 +10,10 @@ use common::{ vol::Vox, }; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub brick_base: (u8, u8, u8), pub floor_base: (u8, u8, u8), diff --git a/world/src/site/settlement/building/archetype/mod.rs b/world/src/site/settlement/building/archetype/mod.rs index a8e67d5aff..de57107619 100644 --- a/world/src/site/settlement/building/archetype/mod.rs +++ b/world/src/site/settlement/building/archetype/mod.rs @@ -4,10 +4,10 @@ pub mod keep; use super::skeleton::*; use crate::{site::BlockMask, IndexRef}; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub house: house::Colors, pub keep: keep::Colors, diff --git a/world/src/site/settlement/building/mod.rs b/world/src/site/settlement/building/mod.rs index d58ee8ad5c..5b7336e0f7 100644 --- a/world/src/site/settlement/building/mod.rs +++ b/world/src/site/settlement/building/mod.rs @@ -10,10 +10,10 @@ pub use self::{ use crate::IndexRef; use common::terrain::Block; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub archetype: archetype::Colors, } diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 196f574bad..00f1db5e12 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -13,9 +13,9 @@ use crate::{ IndexRef, }; use common::{ - assets, + assets::Asset, astar::Astar, - comp::{self, bird_medium, humanoid, object, quadruped_small}, + comp::{self, bird_medium, humanoid, item::ItemAsset, object, quadruped_small}, generation::{ChunkSupplement, EntityInfo}, path::Path, spiral::Spiral2d, @@ -26,11 +26,11 @@ use common::{ use fxhash::FxHasher64; use hashbrown::{HashMap, HashSet}; use rand::prelude::*; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::{collections::VecDeque, f32, hash::BuildHasherDefault}; use vek::*; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize)] pub struct Colors { pub building: building::Colors, @@ -904,7 +904,7 @@ impl Settlement { comp::Alignment::Tame }) .do_if(is_human && rng.gen(), |entity| { - entity.with_main_tool(assets::load_expect_cloned( + entity.with_main_tool(ItemAsset::load_expect_cloned( match rng.gen_range(0, 7) { 0 => "common.items.npc_weapons.tool.broom", 1 => "common.items.npc_weapons.tool.hoe",