Move figure meshing to a background thread.

This commit is contained in:
Joshua Yanovski 2020-08-28 03:02:17 +02:00
parent 1aec2ac6ef
commit 3a96b73b2c
76 changed files with 2589 additions and 2695 deletions

View File

@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Overhauled world colours - Overhauled world colours
- Improved projectile physics - Improved projectile physics
- Improved overhead aiming - Improved overhead aiming
- Figure meshing no longer blocks the main thread.
### Removed ### Removed

View File

@ -1,24 +1,24 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.acacia.1", (
center: (17, 18, 4) specifier: "world.tree.acacia.1",
), center: (17, 18, 4)
( ),
specifier: "world.tree.acacia.2", (
center: (5, 5, 4) specifier: "world.tree.acacia.2",
), center: (5, 5, 4)
( ),
specifier: "world.tree.acacia.3", (
center: (6, 6, 3) specifier: "world.tree.acacia.3",
), center: (6, 6, 3)
( ),
specifier: "world.tree.acacia.4", (
center: (12, 14, 4) specifier: "world.tree.acacia.4",
), center: (12, 14, 4)
( ),
specifier: "world.tree.acacia.5", (
center: (19, 19, 4) specifier: "world.tree.acacia.5",
), center: (19, 19, 4)
] ),
) ]

View File

@ -1,52 +1,52 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.birch.1", (
center: (12, 9, 10) specifier: "world.tree.birch.1",
), center: (12, 9, 10)
( ),
specifier: "world.tree.birch.2", (
center: (12, 10, 10) specifier: "world.tree.birch.2",
), center: (12, 10, 10)
( ),
specifier: "world.tree.birch.3", (
center: (9, 10, 10) specifier: "world.tree.birch.3",
), center: (9, 10, 10)
( ),
specifier: "world.tree.birch.4", (
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.5",
), center: (9, 10, 10)
( ),
specifier: "world.tree.birch.6", (
center: (9, 9, 10) specifier: "world.tree.birch.6",
), center: (9, 9, 10)
( ),
specifier: "world.tree.birch.7", (
center: (10, 10, 10) specifier: "world.tree.birch.7",
), center: (10, 10, 10)
( ),
specifier: "world.tree.birch.8", (
center: (9, 9, 10) specifier: "world.tree.birch.8",
), center: (9, 9, 10)
( ),
specifier: "world.tree.birch.9", (
center: (9, 10, 10) specifier: "world.tree.birch.9",
), center: (9, 10, 10)
( ),
specifier: "world.tree.birch.10", (
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.11",
), center: (9, 10, 10)
( ),
specifier: "world.tree.birch.12", (
center: (9, 10, 10) specifier: "world.tree.birch.12",
), center: (9, 10, 10)
] ),
) ]

View File

@ -1,48 +1,48 @@
( #![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)
),
] [
) (
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)
),
]

View File

@ -1,28 +1,28 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.fruit.1", (
center: (6, 6, 7) specifier: "world.tree.fruit.1",
), center: (6, 6, 7)
( ),
specifier: "world.tree.fruit.2", (
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.3",
), center: (6, 7, 7)
( ),
specifier: "world.tree.fruit.4", (
center: (3, 3, 7) specifier: "world.tree.fruit.4",
), center: (3, 3, 7)
( ),
specifier: "world.tree.fruit.5", (
center: (6, 8, 7) specifier: "world.tree.fruit.5",
), center: (6, 8, 7)
( ),
specifier: "world.tree.fruit.6", (
center: (7, 7, 7) specifier: "world.tree.fruit.6",
), center: (7, 7, 7)
] ),
) ]

View File

@ -1,36 +1,36 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.mangroves.1", (
center: (19, 18, 8) specifier: "world.tree.mangroves.1",
), center: (19, 18, 8)
( ),
specifier: "world.tree.mangroves.2", (
center: (16, 17, 7) specifier: "world.tree.mangroves.2",
), center: (16, 17, 7)
( ),
specifier: "world.tree.mangroves.3", (
center: (18, 19, 8) specifier: "world.tree.mangroves.3",
), center: (18, 19, 8)
( ),
specifier: "world.tree.mangroves.4", (
center: (19, 18, 8) specifier: "world.tree.mangroves.4",
), center: (19, 18, 8)
( ),
specifier: "world.tree.mangroves.5", (
center: (19, 20, 9) specifier: "world.tree.mangroves.5",
), center: (19, 20, 9)
( ),
specifier: "world.tree.mangroves.6", (
center: (18, 21, 9) specifier: "world.tree.mangroves.6",
), center: (18, 21, 9)
( ),
specifier: "world.tree.mangroves.7", (
center: (20, 17, 9) specifier: "world.tree.mangroves.7",
), center: (20, 17, 9)
( ),
specifier: "world.tree.mangroves.8", (
center: (18, 19, 9) specifier: "world.tree.mangroves.8",
), center: (18, 19, 9)
] ),
) ]

View File

@ -1,40 +1,40 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.oak_stump.1", (
center: (15, 18, 10) 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.2",
), center: (15, 18, 10)
( ),
specifier: "world.tree.oak_stump.3", (
center: (16, 20, 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.4",
), center: (18, 21, 10)
( ),
specifier: "world.tree.oak_stump.5", (
center: (18, 18, 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.6",
), center: (16, 21, 10)
( ),
specifier: "world.tree.oak_stump.7", (
center: (20, 19, 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.8",
), center: (22, 20, 10)
( ),
specifier: "world.tree.oak_stump.9", (
center:(26, 26, 10) specifier: "world.tree.oak_stump.9",
), center:(26, 26, 10)
] ),
) ]

View File

@ -1,40 +1,40 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.oak_green.1", (
center: (15, 17, 14) 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.2",
), center: (18, 17, 14)
( ),
specifier: "world.tree.oak_green.3", (
center: (19, 20, 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.4",
), center: (19, 20, 14)
( ),
specifier: "world.tree.oak_green.5", (
center: (18, 18, 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.6",
), center: (18, 21, 14)
( ),
specifier: "world.tree.oak_green.7", (
center: (20, 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.8",
), center: (22, 21, 14)
( ),
specifier: "world.tree.oak_green.9", (
center:(21, 21, 14) specifier: "world.tree.oak_green.9",
), center:(21, 21, 14)
] ),
) ]

View File

@ -1,44 +1,44 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.desert_palm.1", (
center: (7, 8, 2) 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.2",
), center: (8, 7, 2)
( ),
specifier: "world.tree.desert_palm.3", (
center: (7, 8, 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.4",
), center: (6, 7, 2)
( ),
specifier: "world.tree.desert_palm.5", (
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.6",
), center: (7, 7, 2)
( ),
specifier: "world.tree.desert_palm.7", (
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.8",
), center: (5, 7, 2)
( ),
specifier: "world.tree.desert_palm.9", (
center: (7, 7, 2) specifier: "world.tree.desert_palm.9",
), center: (7, 7, 2)
( ),
specifier: "world.tree.desert_palm.10", (
center: (6, 7, 2) specifier: "world.tree.desert_palm.10",
), center: (6, 7, 2)
] ),
) ]

View File

@ -1,36 +1,36 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.pine_green.1", (
center: (15, 15, 14) 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.2",
), center: (15, 15, 14)
( ),
specifier: "world.tree.pine_green.3", (
center: (17, 15, 12) 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.4",
), center: (10, 8, 12)
( ),
specifier: "world.tree.pine_green.5", (
center: (12, 12, 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.6",
), center: (11, 10, 12)
( ),
specifier: "world.tree.pine_green.7", (
center: (16, 15, 12) specifier: "world.tree.pine_green.7",
), center: (16, 15, 12)
( ),
specifier: "world.tree.pine_green.8", (
center: (12, 10, 12) specifier: "world.tree.pine_green.8",
), center: (12, 10, 12)
] ),
) ]

View File

@ -1,12 +1,12 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.structure.natural.witch-hut", (
center: (10, 13, 9) specifier: "world.structure.natural.witch-hut",
), center: (10, 13, 9)
( ),
specifier: "world.structure.natural.tree-house", (
center: (20, 15, 10) specifier: "world.structure.natural.tree-house",
), center: (20, 15, 10)
] ),
) ]

View File

@ -1,16 +1,16 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.structure.natural.ribcage-small", (
center: (7, 13, 4) specifier: "world.structure.natural.ribcage-small",
), center: (7, 13, 4)
( ),
specifier: "world.structure.natural.ribcage-large", (
center: (13, 19, 8) specifier: "world.structure.natural.ribcage-large",
), center: (13, 19, 8)
( ),
specifier: "world.structure.natural.skull-large", (
center: (15, 20, 4) specifier: "world.structure.natural.skull-large",
), center: (15, 20, 4)
] ),
) ]

View File

@ -1,36 +1,36 @@
( #![enable(unwrap_newtypes)]
[
( [
specifier: "world.tree.snow_pine.1", (
center: (15, 15, 14) 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.2",
), center: (15, 15, 14)
( ),
specifier: "world.tree.snow_pine.3", (
center: (17, 15, 12) 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.4",
), center: (10, 8, 12)
( ),
specifier: "world.tree.snow_pine.5", (
center: (12, 12, 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.6",
), center: (11, 10, 12)
( ),
specifier: "world.tree.snow_pine.7", (
center: (16, 15, 12) specifier: "world.tree.snow_pine.7",
), center: (16, 15, 12)
( ),
specifier: "world.tree.snow_pine.8", (
center: (12, 10, 12) specifier: "world.tree.snow_pine.8",
) center: (12, 10, 12)
], ),
) ]

View File

@ -1,14 +1,14 @@
//! Load assets (images or voxel data) from files //! Load assets (images or voxel data) from files
pub mod watch; pub mod watch;
use core::{any::Any, fmt, marker::PhantomData};
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use hashbrown::HashMap; use hashbrown::HashMap;
use image::DynamicImage; use image::DynamicImage;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::{ use std::{
any::Any,
fmt,
fs::{self, File, ReadDir}, fs::{self, File, ReadDir},
io::{BufReader, Read}, io::{BufReader, Read},
path::PathBuf, path::PathBuf,
@ -61,167 +61,16 @@ lazy_static! {
RwLock::new(HashMap::new()); RwLock::new(HashMap::new());
} }
// TODO: Remove this function. It's only used in world/ in a really ugly way.To fn reload<A: Asset>(specifier: &str) -> Result<(), Error>
// do this properly assets should have all their necessary data in one file. A where
// ron file could be used to combine voxel data with positioning data for A::Output: Send + Sync + 'static,
// 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: Asset + 'static, F: FnOnce(A) -> A>(
specifier: &str,
f: F,
) -> Result<Arc<A>, 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<A: Asset + 'static>(specifier: &str) -> Result<Arc<Vec<Arc<A>>>, 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::<Vec<_>>()
});
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::<Vec<_>>(),
);
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::<DynamicImage>("core.ui.backgrounds.city").unwrap();
/// ```
pub fn load<A: Asset + 'static>(specifier: &str) -> Result<Arc<A>, 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<A: Asset + Clone + 'static>(specifier: &str) -> Result<A, Error> {
load::<A>(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::<DynamicImage>("core.ui.backgrounds.city");
/// ```
pub fn load_expect<A: Asset + 'static>(specifier: &str) -> Arc<A> {
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<A: Asset + Clone + 'static>(specifier: &str) -> A {
load_expect::<A>(specifier).as_ref().clone()
}
/// Load an asset while registering it to be watched and reloaded when it
/// changes
pub fn load_watched<A: Asset + 'static>(
specifier: &str,
indicator: &mut watch::ReloadIndicator,
) -> Result<Arc<A>, 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::<A>(&owned_specifier) {
error!(?e, ?owned_specifier, "Error reloading owned_specifier");
}
},
);
Ok(asset)
}
fn reload<A: Asset + 'static>(specifier: &str) -> Result<(), Error> {
let asset = Arc::new(A::parse(load_file(specifier, A::ENDINGS)?)?); let asset = Arc::new(A::parse(load_file(specifier, A::ENDINGS)?)?);
let clone = Arc::clone(&asset);
let mut assets_write = ASSETS.write().unwrap(); let mut assets_write = ASSETS.write().unwrap();
match assets_write.get_mut(specifier) { match assets_write.get_mut(specifier) {
Some(a) => *a = clone, Some(a) => *a = asset,
None => { None => {
assets_write.insert(specifier.to_owned(), clone); assets_write.insert(specifier.to_owned(), asset);
}, },
} }
@ -230,10 +79,189 @@ fn reload<A: Asset + 'static>(specifier: &str) -> Result<(), Error> {
/// The Asset trait, which is implemented by all structures that have their data /// The Asset trait, which is implemented by all structures that have their data
/// stored in the filesystem. /// stored in the filesystem.
pub trait Asset: Send + Sync + Sized { pub trait Asset: Sized {
type Output = Self;
const ENDINGS: &'static [&'static str]; const ENDINGS: &'static [&'static str];
/// Parse the input file and return the correct Asset. /// Parse the input file and return the correct Asset.
fn parse(buf_reader: BufReader<File>) -> Result<Self, Error>; fn parse(buf_reader: BufReader<File>) -> Result<Self::Output, Error>;
// 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<F: FnOnce(Self::Output) -> Self::Output>(
specifier: &str,
f: F,
) -> Result<Arc<Self::Output>, 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<Arc<Vec<Arc<Self::Output>>>, 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::<Vec<_>>()
});
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::<Vec<_>>(),
);
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<Arc<Self::Output>, 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<Self::Output, Error>
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<Self::Output>
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<Arc<Self::Output>, 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::<Self>(&owned_specifier) {
error!(?e, ?owned_specifier, "Error reloading owned_specifier");
}
},
);
Ok(asset)
}
} }
impl Asset for DynamicImage { impl Asset for DynamicImage {
@ -265,13 +293,45 @@ impl Asset for Value {
} }
} }
impl Asset for String { /// Load fron an arbitrary RON file.
const ENDINGS: &'static [&'static str] = &["glsl"]; pub struct Ron<T>(pub PhantomData<T>);
fn parse(mut buf_reader: BufReader<File>) -> Result<Self, Error> { impl<T: Send + Sync + for<'de> Deserialize<'de>> Asset for Ron<T> {
let mut string = String::new(); type Output = T;
buf_reader.read_to_string(&mut string)?;
Ok(string) const ENDINGS: &'static [&'static str] = &["ron"];
fn parse(buf_reader: BufReader<File>) -> Result<T, Error> {
ron::de::from_reader(buf_reader).map_err(Error::parse_error)
}
}
/// Load from a specific asset path.
pub struct AssetWith<T: Asset, const ASSET_PATH: &'static str> {
pub asset: Arc<T::Output>,
}
impl<T: Asset, const ASSET_PATH: &'static str> Clone for AssetWith<T, ASSET_PATH> {
fn clone(&self) -> Self {
Self {
asset: Arc::clone(&self.asset),
}
}
}
impl<T: Asset, const ASSET_PATH: &'static str> AssetWith<T, ASSET_PATH>
where
T::Output: Send + Sync + 'static,
{
#[inline]
pub fn load_watched(indicator: &mut watch::ReloadIndicator) -> Result<Self, Error> {
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(())
} }
} }

View File

@ -5,7 +5,7 @@ pub mod tool;
pub use tool::{Hands, Tool, ToolCategory, ToolKind}; pub use tool::{Hands, Tool, ToolCategory, ToolKind};
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset, Ron},
effect::Effect, effect::Effect,
lottery::Lottery, lottery::Lottery,
terrain::{Block, BlockKind}, terrain::{Block, BlockKind},
@ -14,7 +14,6 @@ use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage}; use specs::{Component, FlaggedStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use std::{fs::File, io::BufReader};
use vek::Rgb; use vek::Rgb;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -90,13 +89,7 @@ pub struct Item {
pub kind: ItemKind, pub kind: ItemKind,
} }
impl Asset for Item { pub type ItemAsset = Ron<Item>;
const ENDINGS: &'static [&'static str] = &["ron"];
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error)
}
}
impl Item { impl Item {
// TODO: consider alternatives such as default abilities that can be added to a // 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::<Self>(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> { pub fn set_amount(&mut self, give_amount: u32) -> Result<(), assets::Error> {
use ItemKind::*; use ItemKind::*;
@ -145,75 +138,44 @@ impl Item {
} }
pub fn try_reclaim_from_block(block: Block) -> Option<Self> { pub fn try_reclaim_from_block(block: Block) -> Option<Self> {
let chosen;
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
match block.kind() { Some(ItemAsset::load_expect_cloned(match block.kind() {
BlockKind::Apple => Some(assets::load_expect_cloned("common.items.food.apple")), BlockKind::Apple => "common.items.food.apple",
BlockKind::Mushroom => Some(assets::load_expect_cloned("common.items.food.mushroom")), BlockKind::Mushroom => "common.items.food.mushroom",
BlockKind::Velorite => Some(assets::load_expect_cloned("common.items.ore.velorite")), BlockKind::Velorite => "common.items.ore.velorite",
BlockKind::VeloriteFrag => { BlockKind::VeloriteFrag => "common.items.ore.veloritefrag",
Some(assets::load_expect_cloned("common.items.ore.veloritefrag")) BlockKind::BlueFlower => "common.items.flowers.blue",
}, BlockKind::PinkFlower => "common.items.flowers.pink",
BlockKind::BlueFlower => Some(assets::load_expect_cloned("common.items.flowers.blue")), BlockKind::PurpleFlower => "common.items.flowers.purple",
BlockKind::PinkFlower => Some(assets::load_expect_cloned("common.items.flowers.pink")), BlockKind::RedFlower => "common.items.flowers.red",
BlockKind::PurpleFlower => { BlockKind::WhiteFlower => "common.items.flowers.white",
Some(assets::load_expect_cloned("common.items.flowers.purple")) BlockKind::YellowFlower => "common.items.flowers.yellow",
}, BlockKind::Sunflower => "common.items.flowers.sun",
BlockKind::RedFlower => Some(assets::load_expect_cloned("common.items.flowers.red")), BlockKind::LongGrass => "common.items.grasses.long",
BlockKind::WhiteFlower => { BlockKind::MediumGrass => "common.items.grasses.medium",
Some(assets::load_expect_cloned("common.items.flowers.white")) BlockKind::ShortGrass => "common.items.grasses.short",
}, BlockKind::Coconut => "common.items.food.coconut",
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")),
BlockKind::Chest => { BlockKind::Chest => {
let chosen = match rng.gen_range(0, 7) { chosen = Lottery::<String>::load_expect(match rng.gen_range(0, 7) {
0 => assets::load_expect::<Lottery<String>>( 0 => "common.loot_tables.loot_table_weapon_uncommon",
"common.loot_tables.loot_table_weapon_uncommon", 1 => "common.loot_tables.loot_table_weapon_common",
), 2 => "common.loot_tables.loot_table_armor_light",
1 => assets::load_expect::<Lottery<String>>( 3 => "common.loot_tables.loot_table_armor_cloth",
"common.loot_tables.loot_table_weapon_common", 4 => "common.loot_tables.loot_table_armor_heavy",
), _ => "common.loot_tables.loot_table_armor_misc",
2 => assets::load_expect::<Lottery<String>>( });
"common.loot_tables.loot_table_armor_light", chosen.choose()
),
3 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_armor_cloth",
),
4 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_armor_heavy",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_armor_misc",
),
};
let chosen = chosen.choose();
Some(assets::load_expect_cloned(chosen))
}, },
BlockKind::Crate => { BlockKind::Crate => {
let chosen = chosen = Lottery::<String>::load_expect("common.loot_tables.loot_table_food");
assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"); chosen.choose()
let chosen = chosen.choose();
Some(assets::load_expect_cloned(chosen))
}, },
BlockKind::Stones => Some(assets::load_expect_cloned( BlockKind::Stones => "common.items.crafting_ing.stones",
"common.items.crafting_ing.stones", BlockKind::Twigs => "common.items.crafting_ing.twigs",
)), BlockKind::ShinyGem => "common.items.crafting_ing.shiny_gem",
BlockKind::Twigs => Some(assets::load_expect_cloned( _ => return None,
"common.items.crafting_ing.twigs", }))
)),
BlockKind::ShinyGem => Some(assets::load_expect_cloned(
"common.items.crafting_ing.shiny_gem",
)),
_ => None,
}
} }
/// Determines whether two items are superficially equivalent to one another /// Determines whether two items are superficially equivalent to one another

View File

@ -1,8 +1,8 @@
pub mod item; pub mod item;
pub mod slot; pub mod slot;
use crate::{assets, recipe::Recipe}; use crate::{assets::Asset, recipe::Recipe};
use item::{Item, ItemKind}; use item::{Item, ItemAsset, ItemKind};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage, HashMapStorage}; use specs::{Component, FlaggedStorage, HashMapStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
@ -517,8 +517,8 @@ impl Default for Inventory {
slots: vec![None; 36], slots: vec![None; 36],
amount: 0, amount: 0,
}; };
inventory.push(assets::load_expect_cloned("common.items.food.cheese")); inventory.push(ItemAsset::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.apple"));
inventory inventory
} }
} }

View File

@ -266,15 +266,16 @@ pub fn swap(
/// ///
/// ``` /// ```
/// use veloren_common::{ /// use veloren_common::{
/// assets, /// assets::Asset,
/// comp::{ /// comp::{
/// item::ItemAsset,
/// slot::{equip, EquipSlot}, /// slot::{equip, EquipSlot},
/// Inventory, Item, /// Inventory, Item,
/// }, /// },
/// LoadoutBuilder, /// LoadoutBuilder,
/// }; /// };
/// ///
/// let boots: Option<Item> = Some(assets::load_expect_cloned( /// let boots: Option<Item> = Some(ItemAsset::load_expect_cloned(
/// "common.items.testing.test_boots", /// "common.items.testing.test_boots",
/// )); /// ));
/// ///
@ -361,7 +362,7 @@ pub fn unequip(slot: EquipSlot, inventory: &mut Inventory, loadout: &mut Loadout
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{assets, LoadoutBuilder}; use crate::{assets::Asset, comp::item::ItemAsset, LoadoutBuilder};
#[test] #[test]
fn test_unequip_items_both_hands() { fn test_unequip_items_both_hands() {
@ -396,11 +397,11 @@ mod tests {
#[test] #[test]
fn test_equip_item() { fn test_equip_item() {
let boots: Option<comp::Item> = Some(assets::load_expect_cloned( let boots: Option<comp::Item> = Some(ItemAsset::load_expect_cloned(
"common.items.testing.test_boots", "common.items.testing.test_boots",
)); ));
let starting_sandles: Option<comp::Item> = Some(assets::load_expect_cloned( let starting_sandles: Option<comp::Item> = Some(ItemAsset::load_expect_cloned(
"common.items.armor.starter.sandals_0", "common.items.armor.starter.sandals_0",
)); ));
@ -425,11 +426,11 @@ mod tests {
#[test] #[test]
fn test_loadout_replace() { fn test_loadout_replace() {
let boots: Option<comp::Item> = Some(assets::load_expect_cloned( let boots: Option<comp::Item> = Some(ItemAsset::load_expect_cloned(
"common.items.testing.test_boots", "common.items.testing.test_boots",
)); ));
let starting_sandles: Option<comp::Item> = Some(assets::load_expect_cloned( let starting_sandles: Option<comp::Item> = Some(ItemAsset::load_expect_cloned(
"common.items.armor.starter.sandals_0", "common.items.armor.starter.sandals_0",
)); ));

View File

@ -1,9 +1,10 @@
use super::*; use super::*;
use crate::assets::Asset;
use lazy_static::lazy_static; use lazy_static::lazy_static;
lazy_static! { lazy_static! {
static ref TEST_ITEMS: Vec<Item> = vec![ static ref TEST_ITEMS: Vec<Item> = vec![
assets::load_expect_cloned("common.items.debug.boost"), item::ItemAsset::load_expect_cloned("common.items.debug.boost"),
assets::load_expect_cloned("common.items.debug.possess") item::ItemAsset::load_expect_cloned("common.items.debug.possess")
]; ];
} }

View File

@ -1,9 +1,12 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![allow(clippy::option_map_unit_fn)] #![allow(clippy::option_map_unit_fn)]
#![allow(incomplete_features)]
#![type_length_limit = "1664759"] #![type_length_limit = "1664759"]
#![feature( #![feature(
arbitrary_enum_discriminant, arbitrary_enum_discriminant,
associated_type_defaults,
const_checked_int_methods, const_checked_int_methods,
const_generics,
fundamental, fundamental,
option_unwrap_none, option_unwrap_none,
bool_to_option, bool_to_option,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
assets, assets::Asset,
comp::{ comp::{
item::{Item, ItemKind}, item::{Item, ItemAsset, ItemKind},
Body, CharacterAbility, ItemConfig, Loadout, Body, CharacterAbility, ItemConfig, Loadout,
}, },
}; };
@ -48,16 +48,16 @@ impl LoadoutBuilder {
/// Set default armor items for the loadout. This may vary with game /// Set default armor items for the loadout. This may vary with game
/// updates, but should be safe defaults for a new character. /// updates, but should be safe defaults for a new character.
pub fn defaults(self) -> Self { 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", "common.items.armor.starter.rugged_chest",
))) )))
.pants(Some(assets::load_expect_cloned( .pants(Some(ItemAsset::load_expect_cloned(
"common.items.armor.starter.rugged_pants", "common.items.armor.starter.rugged_pants",
))) )))
.foot(Some(assets::load_expect_cloned( .foot(Some(ItemAsset::load_expect_cloned(
"common.items.armor.starter.sandals_0", "common.items.armor.starter.sandals_0",
))) )))
.lantern(Some(assets::load_expect_cloned( .lantern(Some(ItemAsset::load_expect_cloned(
"common.items.armor.starter.lantern", "common.items.armor.starter.lantern",
))) )))
} }
@ -66,7 +66,7 @@ impl LoadoutBuilder {
pub fn animal(body: Body) -> Self { pub fn animal(body: Body) -> Self {
Self(Loadout { Self(Loadout {
active_item: Some(ItemConfig { 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 { ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 10, energy_cost: 10,
buildup_duration: Duration::from_millis(600), buildup_duration: Duration::from_millis(600),
@ -125,7 +125,7 @@ impl LoadoutBuilder {
/// Get an [Item](../comp/struct.Item.html) by its string /// Get an [Item](../comp/struct.Item.html) by its string
/// reference by loading its asset /// reference by loading its asset
pub fn item_from_str(item_ref: Option<&str>) -> Option<Item> { pub fn item_from_str(item_ref: Option<&str>) -> Option<Item> {
item_ref.and_then(|specifier| assets::load_cloned::<Item>(&specifier).ok()) item_ref.and_then(|specifier| ItemAsset::load_cloned(&specifier).ok())
} }
/// Get an item's (weapon's) default /// Get an item's (weapon's) default

View File

@ -1,9 +1,9 @@
use crate::assets::{self, Asset}; use crate::assets::{self, Asset};
use rand::prelude::*; use rand::prelude::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize};
use std::{fs::File, io::BufReader}; use std::{fs::File, io::BufReader};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct Lottery<T> { pub struct Lottery<T> {
items: Vec<(f32, T)>, items: Vec<(f32, T)>,
total: f32, total: f32,
@ -48,14 +48,14 @@ impl<T> Lottery<T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{assets, comp::Item}; use crate::comp::item::ItemAsset;
#[test] #[test]
fn test_loot_table() { fn test_loot_table() {
let test = assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table"); let test = Lottery::<String>::load_expect("common.loot_tables.loot_table");
for (_, item) in test.iter() { for (_, item) in test.iter() {
assert!( assert!(
assets::load::<Item>(item).is_ok(), ItemAsset::load(item).is_ok(),
"Invalid loot table item '{}'", "Invalid loot table item '{}'",
item item
); );

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
assets, assets::Asset,
comp::{self, AllBodies, Body}, comp::{self, AllBodies, Body},
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -63,7 +63,7 @@ pub struct SpeciesNames {
pub type NpcNames = AllBodies<BodyNames, SpeciesNames>; pub type NpcNames = AllBodies<BodyNames, SpeciesNames>;
lazy_static! { lazy_static! {
pub static ref NPC_NAMES: Arc<NpcNames> = assets::load_expect("common.npc_names"); pub static ref NPC_NAMES: Arc<NpcNames> = NpcNames::load_expect("common.npc_names");
} }
impl FromStr for NpcKind { impl FromStr for NpcKind {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset},
comp::{Inventory, Item}, comp::{item::ItemAsset, Inventory, Item},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -78,12 +78,12 @@ impl Asset for RecipeBook {
.map::<Result<(String, Recipe), assets::Error>, _>( .map::<Result<(String, Recipe), assets::Error>, _>(
|(name, ((output, amount), inputs))| { |(name, ((output, amount), inputs))| {
Ok((name, Recipe { Ok((name, Recipe {
output: ((&*assets::load::<Item>(&output)?).clone(), amount), output: ((&*ItemAsset::load(&output)?).clone(), amount),
inputs: inputs inputs: inputs
.into_iter() .into_iter()
.map::<Result<(Item, usize), assets::Error>, _>( .map::<Result<(Item, usize), assets::Error>, _>(
|(name, amount)| { |(name, amount)| {
Ok(((&*assets::load::<Item>(&name)?).clone(), amount)) Ok(((&*ItemAsset::load(&name)?).clone(), amount))
}, },
) )
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
@ -96,4 +96,4 @@ impl Asset for RecipeBook {
} }
} }
pub fn default_recipe_book() -> Arc<RecipeBook> { assets::load_expect("common.recipe_book") } pub fn default_recipe_book() -> Arc<RecipeBook> { RecipeBook::load_expect("common.recipe_book") }

View File

@ -1,6 +1,6 @@
use super::BlockKind; use super::BlockKind;
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset, Ron},
make_case_elim, make_case_elim,
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}, vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::{Dyna, DynaError}, volumes::dyna::{Dyna, DynaError},
@ -53,15 +53,11 @@ pub struct Structure {
impl Structure { impl Structure {
pub fn load_group(specifier: &str) -> Vec<Arc<Structure>> { pub fn load_group(specifier: &str) -> Vec<Arc<Structure>> {
let spec = assets::load::<StructuresSpec>(&["world.manifests.", specifier].concat()); let spec = StructuresSpec::load_expect(&["world.manifests.", specifier].concat());
spec.unwrap() spec.iter()
.0
.iter()
.map(|sp| { .map(|sp| {
assets::load_map(&sp.specifier[..], |s: Structure| { Structure::load_map(&sp.specifier[..], |s| s.with_center(Vec3::from(sp.center)))
s.with_center(Vec3::from(sp.center)) .unwrap()
})
.unwrap()
}) })
.collect() .collect()
} }
@ -170,13 +166,5 @@ struct StructureSpec {
specifier: String, specifier: String,
center: [i32; 3], center: [i32; 3],
} }
#[derive(Deserialize)]
struct StructuresSpec(Vec<StructureSpec>);
impl Asset for StructuresSpec { type StructuresSpec = Ron<Vec<StructureSpec>>;
const ENDINGS: &'static [&'static str] = &["ron"];
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error)
}
}

View File

@ -5,9 +5,9 @@
use crate::{client::Client, Server, StateExt}; use crate::{client::Client, Server, StateExt};
use chrono::{NaiveTime, Timelike}; use chrono::{NaiveTime, Timelike};
use common::{ use common::{
assets, assets::Asset,
cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS}, cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS},
comp::{self, ChatType, Item, LightEmitter, WaypointArea}, comp::{self, item::ItemAsset, ChatType, Item, LightEmitter, WaypointArea},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
msg::{Notification, PlayerListUpdate, ServerMsg}, msg::{Notification, PlayerListUpdate, ServerMsg},
npc::{self, get_npc_name}, npc::{self, get_npc_name},
@ -117,7 +117,7 @@ fn handle_give_item(
scan_fmt_some!(&args, &action.arg_fmt(), String, u32) scan_fmt_some!(&args, &action.arg_fmt(), String, u32)
{ {
let give_amount = give_amount_opt.unwrap_or(1); 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; let mut item: Item = item;
if let Ok(()) = item.set_amount(give_amount.min(2000)) { if let Ok(()) = item.set_amount(give_amount.min(2000)) {
server server
@ -1640,7 +1640,7 @@ fn handle_debug(
_args: String, _args: String,
_action: &ChatCommand, _action: &ChatCommand,
) { ) {
if let Ok(items) = assets::load_glob::<Item>("common.items.debug.*") { if let Ok(items) = ItemAsset::load_glob("common.items.debug.*") {
server server
.state() .state()
.ecs() .ecs()

View File

@ -1,9 +1,9 @@
use crate::{client::Client, comp::quadruped_small, Server, SpawnPoint, StateExt}; use crate::{client::Client, comp::quadruped_small, Server, SpawnPoint, StateExt};
use common::{ use common::{
assets, assets::Asset,
comp::{ comp::{
self, object, Alignment, Body, Damage, DamageSource, Group, HealthChange, HealthSource, self, item::ItemAsset, object, Alignment, Body, Damage, DamageSource, Group, HealthChange,
Player, Pos, Stats, HealthSource, Player, Pos, Stats,
}, },
lottery::Lottery, lottery::Lottery,
msg::{PlayerListUpdate, ServerMsg}, 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 // Decide for a loot drop before turning into a lootbag
let old_body = state.ecs().write_storage::<Body>().remove(entity); let old_body = state.ecs().write_storage::<Body>().remove(entity);
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let drop = match old_body { let drop = Lottery::<String>::load_expect(match old_body {
Some(common::comp::Body::Humanoid(_)) => match rng.gen_range(0, 4) { Some(common::comp::Body::Humanoid(_)) => match rng.gen_range(0, 4) {
0 => assets::load_expect::<Lottery<String>>( 0 => "common.loot_tables.loot_table_humanoids",
"common.loot_tables.loot_table_humanoids", 1 => "common.loot_tables.loot_table_armor_light",
), 2 => "common.loot_tables.loot_table_armor_cloth",
1 => assets::load_expect::<Lottery<String>>( 3 => "common.loot_tables.loot_table_weapon_common",
"common.loot_tables.loot_table_armor_light", _ => "common.loot_tables.loot_table_humanoids",
),
2 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_armor_cloth",
),
3 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_common",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_humanoids",
),
}, },
Some(common::comp::Body::QuadrupedSmall(quadruped_small)) => { Some(common::comp::Body::QuadrupedSmall(quadruped_small)) => {
match quadruped_small.species { match quadruped_small.species {
quadruped_small::Species::Dodarock => match rng.gen_range(0, 6) { quadruped_small::Species::Dodarock => match rng.gen_range(0, 6) {
0 => assets::load_expect::<Lottery<String>>( 0 => "common.loot_tables.loot_table_armor_misc",
"common.loot_tables.loot_table_armor_misc", 1 => "common.loot_tables.loot_table_rocks",
), _ => "common.loot_tables.loot_table_rocks",
1 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_rocks",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_rocks",
),
}, },
_ => match rng.gen_range(0, 4) { _ => match rng.gen_range(0, 4) {
0 => assets::load_expect::<Lottery<String>>( 0 => "common.loot_tables.loot_table_food",
"common.loot_tables.loot_table_food", 1 => "common.loot_tables.loot_table_armor_misc",
), 2 => "common.loot_tables.loot_table_animal_parts",
1 => assets::load_expect::<Lottery<String>>( _ => "common.loot_tables.loot_table_animal_parts",
"common.loot_tables.loot_table_armor_misc",
),
2 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_animal_parts",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_animal_parts",
),
}, },
} }
}, },
Some(common::comp::Body::QuadrupedMedium(_)) => match rng.gen_range(0, 4) { Some(common::comp::Body::QuadrupedMedium(_)) => match rng.gen_range(0, 4) {
0 => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"), 0 => "common.loot_tables.loot_table_food",
1 => assets::load_expect::<Lottery<String>>( 1 => "common.loot_tables.loot_table_armor_misc",
"common.loot_tables.loot_table_armor_misc", 2 => "common.loot_tables.loot_table_animal_parts",
), _ => "common.loot_tables.loot_table_animal_parts",
2 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_animal_parts",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_animal_parts",
),
}, },
Some(common::comp::Body::BirdMedium(_)) => match rng.gen_range(0, 3) { Some(common::comp::Body::BirdMedium(_)) => match rng.gen_range(0, 3) {
0 => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"), 0 => "common.loot_tables.loot_table_food",
1 => assets::load_expect::<Lottery<String>>( 1 => "common.loot_tables.loot_table_armor_misc",
"common.loot_tables.loot_table_armor_misc", _ => "common.loot_tables.loot_table",
),
_ => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table"),
}, },
Some(common::comp::Body::BipedLarge(_)) => match rng.gen_range(0, 8) { Some(common::comp::Body::BipedLarge(_)) => match rng.gen_range(0, 8) {
0 => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"), 0 => "common.loot_tables.loot_table_food",
1 => assets::load_expect::<Lottery<String>>( 1 => "common.loot_tables.loot_table_armor_nature",
"common.loot_tables.loot_table_armor_nature", 3 => "common.loot_tables.loot_table_armor_heavy",
), 5 => "common.loot_tables.loot_table_weapon_uncommon",
3 => assets::load_expect::<Lottery<String>>( 6 => "common.loot_tables.loot_table_weapon_rare",
"common.loot_tables.loot_table_armor_heavy", _ => "common.loot_tables.loot_table_cave_large",
),
5 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_uncommon",
),
6 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_rare",
),
_ => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_cave_large",
),
}, },
Some(common::comp::Body::Golem(_)) => match rng.gen_range(0, 9) { Some(common::comp::Body::Golem(_)) => match rng.gen_range(0, 9) {
0 => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"), 0 => "common.loot_tables.loot_table_food",
1 => assets::load_expect::<Lottery<String>>( 1 => "common.loot_tables.loot_table_armor_misc",
"common.loot_tables.loot_table_armor_misc", 2 => "common.loot_tables.loot_table_armor_light",
), 3 => "common.loot_tables.loot_table_armor_heavy",
2 => assets::load_expect::<Lottery<String>>( 4 => "common.loot_tables.loot_table_armor_misc",
"common.loot_tables.loot_table_armor_light", 5 => "common.loot_tables.loot_table_weapon_common",
), 6 => "common.loot_tables.loot_table_weapon_uncommon",
3 => assets::load_expect::<Lottery<String>>( 7 => "common.loot_tables.loot_table_weapon_rare",
"common.loot_tables.loot_table_armor_heavy", _ => "common.loot_tables.loot_table",
),
4 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_armor_misc",
),
5 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_common",
),
6 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_uncommon",
),
7 => assets::load_expect::<Lottery<String>>(
"common.loot_tables.loot_table_weapon_rare",
),
_ => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table"),
},
Some(common::comp::Body::Critter(_)) => {
assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_animal_parts")
},
Some(common::comp::Body::Dragon(_)) => {
assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_weapon_rare")
}, },
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) { Some(common::comp::Body::QuadrupedLow(_)) => match rng.gen_range(0, 3) {
0 => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table_food"), 0 => "common.loot_tables.loot_table_food",
1 => assets::load_expect::<Lottery<String>>( 1 => "common.loot_tables.loot_table_animal_parts",
"common.loot_tables.loot_table_animal_parts", _ => "common.loot_tables.loot_table",
),
_ => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table"),
}, },
_ => assets::load_expect::<Lottery<String>>("common.loot_tables.loot_table"), _ => "common.loot_tables.loot_table",
}; });
let drop = drop.choose(); let drop = drop.choose();
// Replace npc with lootbag containing drop // Replace npc with lootbag containing drop
let _ = state let _ = state
@ -321,7 +259,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
item_drops.remove(entity); item_drops.remove(entity);
item_drop.0 item_drop.0
} else { } else {
assets::load_expect_cloned(drop) ItemAsset::load_expect_cloned(drop)
}; };
let _ = state.ecs().write_storage().insert(entity, item); let _ = state.ecs().write_storage().insert(entity, item);

View File

@ -3,7 +3,7 @@ use crate::{
Server, Server,
}; };
use common::{ use common::{
assets, assets::Asset,
comp::{self, item}, comp::{self, item},
msg::ServerMsg, msg::ServerMsg,
sync::{Uid, WorldSyncExt}, 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") .expect("Could not read loadouts component while possessing")
.or_insert(comp::Loadout::default()); .or_insert(comp::Loadout::default());
let item = assets::load_expect_cloned::<comp::Item>("common.items.debug.possess"); let item = item::ItemAsset::load_expect_cloned("common.items.debug.possess");
if let item::ItemKind::Tool(tool) = &item.kind { if let item::ItemKind::Tool(tool) = &item.kind {
let mut abilities = tool.get_abilities(); let mut abilities = tool.get_abilities();
let mut ability_drain = abilities.drain(..); let mut ability_drain = abilities.drain(..);

View File

@ -1,8 +1,12 @@
use super::SysTimer; use super::SysTimer;
use crate::{chunk_generator::ChunkGenerator, client::Client, Tick}; use crate::{chunk_generator::ChunkGenerator, client::Client, Tick};
use common::{ use common::{
assets, assets::Asset,
comp::{self, bird_medium, item, Alignment, CharacterAbility, ItemConfig, Player, Pos}, comp::{
self, bird_medium,
item::{self, ItemAsset},
Alignment, CharacterAbility, ItemConfig, Player, Pos,
},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
generation::get_npc_name, generation::get_npc_name,
msg::ServerMsg, msg::ServerMsg,
@ -135,7 +139,7 @@ impl<'a> System<'a> for Sys {
} else { } else {
Some(ItemConfig { Some(ItemConfig {
// We need the empty item so npcs can attack // 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 { ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 0, energy_cost: 0,
buildup_duration: Duration::from_millis(0), buildup_duration: Duration::from_millis(0),
@ -156,7 +160,7 @@ impl<'a> System<'a> for Sys {
active_item, active_item,
second_item: None, second_item: None,
shoulder: None, shoulder: None,
chest: Some(assets::load_expect_cloned( chest: Some(ItemAsset::load_expect_cloned(
match rand::thread_rng().gen_range(0, 10) { match rand::thread_rng().gen_range(0, 10) {
0 => "common.items.npc_armor.chest.worker_green_0", 0 => "common.items.npc_armor.chest.worker_green_0",
1 => "common.items.npc_armor.chest.worker_green_1", 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", _ => "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", "common.items.armor.belt.leather_0",
)), )),
hand: None, hand: None,
pants: Some(assets::load_expect_cloned( pants: Some(ItemAsset::load_expect_cloned(
"common.items.armor.pants.worker_blue_0", "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) { match rand::thread_rng().gen_range(0, 2) {
0 => "common.items.armor.foot.leather_0", 0 => "common.items.armor.foot.leather_0",
_ => "common.items.armor.starter.sandals_0", _ => "common.items.armor.starter.sandals_0",
@ -193,30 +197,32 @@ impl<'a> System<'a> for Sys {
comp::Alignment::Enemy => comp::Loadout { comp::Alignment::Enemy => comp::Loadout {
active_item, active_item,
second_item: None, second_item: None,
shoulder: Some(assets::load_expect_cloned( shoulder: Some(ItemAsset::load_expect_cloned(
"common.items.npc_armor.shoulder.cultist_shoulder_purple", "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", "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", "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", "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", "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", "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", "common.items.npc_armor.back.dungeon_purple-0",
)), )),
ring: None, ring: None,
neck: 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, head: None,
tabard: None, tabard: None,
}, },
@ -259,7 +265,7 @@ impl<'a> System<'a> for Sys {
} }
loadout = comp::Loadout { loadout = comp::Loadout {
active_item: Some(comp::ItemConfig { active_item: Some(comp::ItemConfig {
item: assets::load_expect_cloned( item: ItemAsset::load_expect_cloned(
"common.items.npc_weapons.sword.zweihander_sword_0", "common.items.npc_weapons.sword.zweihander_sword_0",
), ),
ability1: Some(CharacterAbility::BasicMelee { ability1: Some(CharacterAbility::BasicMelee {
@ -276,22 +282,22 @@ impl<'a> System<'a> for Sys {
dodge_ability: None, dodge_ability: None,
}), }),
second_item: None, second_item: None,
shoulder: Some(assets::load_expect_cloned( shoulder: Some(ItemAsset::load_expect_cloned(
"common.items.armor.shoulder.plate_0", "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", "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", "common.items.armor.belt.plate_0",
)), )),
hand: Some(assets::load_expect_cloned( hand: Some(ItemAsset::load_expect_cloned(
"common.items.armor.hand.plate_0", "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", "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", "common.items.armor.foot.plate_0",
)), )),
back: None, back: None,

View File

@ -5,10 +5,14 @@ use std::{
}; };
use structopt::StructOpt; use structopt::StructOpt;
use common::{assets, comp}; use common::{
assets::{self, Asset},
comp,
};
use comp::item::{ use comp::item::{
armor::{ArmorKind, Protection}, armor::{ArmorKind, Protection},
tool::ToolKind, tool::ToolKind,
ItemAsset,
}; };
#[derive(StructOpt)] #[derive(StructOpt)]
@ -43,7 +47,7 @@ fn armor_stats() -> Result<(), Box<dyn Error>> {
.to_string() .to_string()
.replace("/", "."); .replace("/", ".");
let asset = assets::load_expect_cloned::<comp::Item>(asset_identifier); let asset = ItemAsset::load_expect_cloned(asset_identifier);
match &asset.kind { match &asset.kind {
comp::item::ItemKind::Armor(armor) => { comp::item::ItemKind::Armor(armor) => {
@ -109,7 +113,7 @@ fn weapon_stats() -> Result<(), Box<dyn Error>> {
.display() .display()
.to_string() .to_string()
.replace("/", "."); .replace("/", ".");
let asset = assets::load_expect_cloned::<comp::Item>(asset_identifier); let asset = ItemAsset::load_expect_cloned(asset_identifier);
match &asset.kind { match &asset.kind {
comp::item::ItemKind::Tool(tool) => { comp::item::ItemKind::Tool(tool) => {

View File

@ -10,10 +10,12 @@ pub use self::{
wield::WieldAnimation, wield::WieldAnimation,
}; };
use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; use super::{make_bone, vek::*, FigureBoneData, Skeleton};
use common::comp::{self}; use common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::biped_large::Body;
skeleton_impls!(struct BipedLargeSkeleton { skeleton_impls!(struct BipedLargeSkeleton {
+ head, + head,
+ jaw, + jaw,
@ -36,6 +38,7 @@ skeleton_impls!(struct BipedLargeSkeleton {
impl Skeleton for BipedLargeSkeleton { impl Skeleton for BipedLargeSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 15; const BONE_COUNT: usize = 15;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -115,8 +118,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::biped_large::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::biped_large::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::biped_large::{BodyType::*, Species::*}; use comp::biped_large::{BodyType::*, Species::*};
Self { Self {
head: match (body.species, body.body_type) { head: match (body.species, body.body_type) {

View File

@ -6,10 +6,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{feed::FeedAnimation, fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::bird_medium::Body;
skeleton_impls!(struct BirdMediumSkeleton { skeleton_impls!(struct BirdMediumSkeleton {
+ head, + head,
+ torso, + torso,
@ -22,6 +24,7 @@ skeleton_impls!(struct BirdMediumSkeleton {
impl Skeleton for BirdMediumSkeleton { impl Skeleton for BirdMediumSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 7; const BONE_COUNT: usize = 7;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -82,8 +85,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::bird_medium::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::bird_medium::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::bird_medium::Species::*; use comp::bird_medium::Species::*;
Self { Self {
head: match (body.species, body.body_type) { head: match (body.species, body.body_type) {

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::bird_small::Body;
skeleton_impls!(struct BirdSmallSkeleton { skeleton_impls!(struct BirdSmallSkeleton {
+ head, + head,
+ torso, + torso,
@ -18,6 +20,7 @@ skeleton_impls!(struct BirdSmallSkeleton {
impl Skeleton for BirdSmallSkeleton { impl Skeleton for BirdSmallSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 4; const BONE_COUNT: usize = 4;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -59,6 +62,6 @@ impl Default for SkeletonAttr {
fn default() -> Self { Self } fn default() -> Self { Self }
} }
impl<'a> From<&'a comp::bird_small::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a comp::bird_small::Body) -> Self { Self } fn from(_body: &'a Body) -> Self { Self }
} }

View File

@ -36,10 +36,12 @@ pub use self::{
swimwield::SwimWieldAnimation, wield::WieldAnimation, swimwield::SwimWieldAnimation, wield::WieldAnimation,
}; };
use super::{make_bone, vek::*, Bone, FigureBoneData, Skeleton}; use super::{make_bone, vek::*, FigureBoneData, Skeleton};
use common::comp; use common::comp;
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::humanoid::Body;
skeleton_impls!(struct CharacterSkeleton { skeleton_impls!(struct CharacterSkeleton {
+ head, + head,
+ chest, + chest,
@ -65,6 +67,7 @@ skeleton_impls!(struct CharacterSkeleton {
impl Skeleton for CharacterSkeleton { impl Skeleton for CharacterSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 16; const BONE_COUNT: usize = 16;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -156,7 +159,7 @@ impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr {
} }
impl SkeletonAttr { impl SkeletonAttr {
pub fn calculate_scale(body: &comp::humanoid::Body) -> f32 { pub fn calculate_scale(body: &Body) -> f32 {
use comp::humanoid::{BodyType::*, Species::*}; use comp::humanoid::{BodyType::*, Species::*};
match (body.species, body.body_type) { match (body.species, body.body_type) {
(Orc, Male) => 1.14, (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 #[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::*}; use comp::humanoid::{BodyType::*, Species::*};
Self { Self {
scaler: SkeletonAttr::calculate_scale(body), scaler: SkeletonAttr::calculate_scale(body),

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::critter::Body;
skeleton_impls!(struct CritterSkeleton { skeleton_impls!(struct CritterSkeleton {
+ head, + head,
+ chest, + chest,
@ -27,6 +29,7 @@ pub struct CritterAttr {
impl Skeleton for CritterSkeleton { impl Skeleton for CritterSkeleton {
type Attr = CritterAttr; type Attr = CritterAttr;
type Body = Body;
const BONE_COUNT: usize = 5; const BONE_COUNT: usize = 5;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -84,8 +87,8 @@ impl Default for CritterAttr {
} }
} }
impl<'a> From<&'a comp::critter::Body> for CritterAttr { impl<'a> From<&'a Body> for CritterAttr {
fn from(body: &'a comp::critter::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::critter::Species::*; use comp::critter::Species::*;
Self { Self {
head: match (body.species, body.body_type) { head: match (body.species, body.body_type) {

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{fly::FlyAnimation, idle::IdleAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::dragon::Body;
skeleton_impls!(struct DragonSkeleton { skeleton_impls!(struct DragonSkeleton {
+ head_upper, + head_upper,
+ head_lower, + head_lower,
@ -29,6 +31,7 @@ skeleton_impls!(struct DragonSkeleton {
impl Skeleton for DragonSkeleton { impl Skeleton for DragonSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 15; const BONE_COUNT: usize = 15;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -115,8 +118,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::dragon::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::dragon::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::dragon::Species::*; use comp::dragon::Species::*;
Self { Self {
head_upper: match (body.species, body.body_type) { head_upper: match (body.species, body.body_type) {

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::fish_medium::Body;
skeleton_impls!(struct FishMediumSkeleton { skeleton_impls!(struct FishMediumSkeleton {
+ head, + head,
+ torso, + torso,
@ -20,6 +22,7 @@ skeleton_impls!(struct FishMediumSkeleton {
impl Skeleton for FishMediumSkeleton { impl Skeleton for FishMediumSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 6; const BONE_COUNT: usize = 6;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -63,6 +66,6 @@ impl Default for SkeletonAttr {
fn default() -> Self { Self } fn default() -> Self { Self }
} }
impl<'a> From<&'a comp::fish_medium::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a comp::fish_medium::Body) -> Self { Self } fn from(_body: &'a Body) -> Self { Self }
} }

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::fish_small::Body;
skeleton_impls!(struct FishSmallSkeleton { skeleton_impls!(struct FishSmallSkeleton {
+ torso, + torso,
+ tail, + tail,
@ -16,6 +18,7 @@ skeleton_impls!(struct FishSmallSkeleton {
impl Skeleton for FishSmallSkeleton { impl Skeleton for FishSmallSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 2; const BONE_COUNT: usize = 2;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -55,6 +58,6 @@ impl Default for SkeletonAttr {
fn default() -> Self { Self } fn default() -> Self { Self }
} }
impl<'a> From<&'a comp::fish_small::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a comp::fish_small::Body) -> Self { Self } fn from(_body: &'a Body) -> Self { Self }
} }

View File

@ -1,5 +1,7 @@
use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use super::{make_bone, vek::*, FigureBoneData, Skeleton};
pub type Body = ();
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct FixtureSkeleton; pub struct FixtureSkeleton;
@ -17,6 +19,7 @@ impl<'a, Factor> Lerp<Factor> for &'a FixtureSkeleton {
impl Skeleton for FixtureSkeleton { impl Skeleton for FixtureSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 1; const BONE_COUNT: usize = 1;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -33,3 +36,11 @@ impl Skeleton for FixtureSkeleton {
Vec3::default() Vec3::default()
} }
} }
impl Default for SkeletonAttr {
fn default() -> Self { Self }
}
impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a Body) -> Self { Self }
}

View File

@ -5,10 +5,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::golem::Body;
skeleton_impls!(struct GolemSkeleton { skeleton_impls!(struct GolemSkeleton {
+ head, + head,
+ upper_torso, + upper_torso,
@ -25,6 +27,7 @@ skeleton_impls!(struct GolemSkeleton {
impl Skeleton for GolemSkeleton { impl Skeleton for GolemSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 10; const BONE_COUNT: usize = 10;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -90,8 +93,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::golem::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::golem::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::golem::Species::*; use comp::golem::Species::*;
Self { Self {
head: match (body.species, body.body_type) { head: match (body.species, body.body_type) {

View File

@ -9,14 +9,14 @@ macro_rules! skeleton_impls {
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct $Skeleton { pub struct $Skeleton {
$( $(
$bone: Bone, $bone: $crate::Bone,
)* )*
} }
impl<'a, Factor> Lerp<Factor> for &'a $Skeleton impl<'a, Factor> $crate::vek::Lerp<Factor> for &'a $Skeleton
where where
Factor: Copy, Factor: Copy,
Bone: Lerp<Factor, Output=Bone> $crate::Bone: Lerp<Factor, Output=$crate::Bone>
{ {
type Output = $Skeleton; type Output = $Skeleton;
@ -79,6 +79,7 @@ pub type Bone = Transform<f32, f32, f32>;
pub trait Skeleton: Send + Sync + 'static { pub trait Skeleton: Send + Sync + 'static {
type Attr; type Attr;
type Body;
const BONE_COUNT: usize; const BONE_COUNT: usize;

View File

@ -1,4 +1,7 @@
use super::{make_bone, vek::*, FigureBoneData, Skeleton}; use super::{make_bone, vek::*, FigureBoneData, Skeleton};
use common::comp::{self};
pub type Body = comp::object::Body;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct ObjectSkeleton; pub struct ObjectSkeleton;
@ -19,6 +22,7 @@ const SCALE: f32 = 1.0 / 11.0;
impl Skeleton for ObjectSkeleton { impl Skeleton for ObjectSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 1; const BONE_COUNT: usize = 1;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -34,3 +38,11 @@ impl Skeleton for ObjectSkeleton {
Vec3::default() Vec3::default()
} }
} }
impl Default for SkeletonAttr {
fn default() -> Self { Self }
}
impl<'a> From<&'a Body> for SkeletonAttr {
fn from(_body: &'a Body) -> Self { Self }
}

View File

@ -8,10 +8,12 @@ pub use self::{
alpha::AlphaAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::quadruped_low::Body;
skeleton_impls!(struct QuadrupedLowSkeleton { skeleton_impls!(struct QuadrupedLowSkeleton {
+ head_upper, + head_upper,
+ head_lower, + head_lower,
@ -27,6 +29,7 @@ skeleton_impls!(struct QuadrupedLowSkeleton {
impl Skeleton for QuadrupedLowSkeleton { impl Skeleton for QuadrupedLowSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 10; const BONE_COUNT: usize = 10;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -102,8 +105,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::quadruped_low::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::quadruped_low::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::quadruped_low::Species::*; use comp::quadruped_low::Species::*;
Self { Self {
head_upper: match (body.species, body.body_type) { head_upper: match (body.species, body.body_type) {

View File

@ -8,10 +8,12 @@ pub use self::{
alpha::AlphaAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::quadruped_medium::Body;
skeleton_impls!(struct QuadrupedMediumSkeleton { skeleton_impls!(struct QuadrupedMediumSkeleton {
+ head_upper, + head_upper,
+ head_lower, + head_lower,
@ -32,6 +34,7 @@ skeleton_impls!(struct QuadrupedMediumSkeleton {
impl Skeleton for QuadrupedMediumSkeleton { impl Skeleton for QuadrupedMediumSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 15; const BONE_COUNT: usize = 15;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -124,8 +127,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::quadruped_medium::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::quadruped_medium::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::quadruped_medium::Species::*; use comp::quadruped_medium::Species::*;
Self { Self {
head_upper: match (body.species, body.body_type) { head_upper: match (body.species, body.body_type) {

View File

@ -6,10 +6,12 @@ pub mod run;
// Reexports // Reexports
pub use self::{feed::FeedAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation}; 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 common::comp::{self};
use core::convert::TryFrom; use core::convert::TryFrom;
pub type Body = comp::quadruped_small::Body;
skeleton_impls!(struct QuadrupedSmallSkeleton { skeleton_impls!(struct QuadrupedSmallSkeleton {
+ head, + head,
+ chest, + chest,
@ -22,6 +24,7 @@ skeleton_impls!(struct QuadrupedSmallSkeleton {
impl Skeleton for QuadrupedSmallSkeleton { impl Skeleton for QuadrupedSmallSkeleton {
type Attr = SkeletonAttr; type Attr = SkeletonAttr;
type Body = Body;
const BONE_COUNT: usize = 7; const BONE_COUNT: usize = 7;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -90,8 +93,8 @@ impl Default for SkeletonAttr {
} }
} }
impl<'a> From<&'a comp::quadruped_small::Body> for SkeletonAttr { impl<'a> From<&'a Body> for SkeletonAttr {
fn from(body: &'a comp::quadruped_small::Body) -> Self { fn from(body: &'a Body) -> Self {
use comp::quadruped_small::Species::*; use comp::quadruped_small::Species::*;
Self { Self {
head: match (body.species, body.body_type) { head: match (body.species, body.body_type) {

View File

@ -1,8 +1,11 @@
use super::*; use super::*;
use crate::audio::sfx::SfxEvent; use crate::audio::sfx::SfxEvent;
use common::{ use common::{
assets, assets::Asset,
comp::{item::tool::ToolCategory, CharacterAbilityType, CharacterState, ItemConfig, Loadout}, comp::{
item::{tool::ToolCategory, ItemAsset},
CharacterAbilityType, CharacterState, ItemConfig, Loadout,
},
states, states,
}; };
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -12,7 +15,7 @@ fn maps_wield_while_equipping() {
let mut loadout = Loadout::default(); let mut loadout = Loadout::default();
loadout.active_item = Some(ItemConfig { 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, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,
@ -40,7 +43,7 @@ fn maps_unwield() {
let mut loadout = Loadout::default(); let mut loadout = Loadout::default();
loadout.active_item = Some(ItemConfig { 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, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,
@ -66,7 +69,7 @@ fn maps_basic_melee() {
let mut loadout = Loadout::default(); let mut loadout = Loadout::default();
loadout.active_item = Some(ItemConfig { 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, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,
@ -102,7 +105,7 @@ fn matches_ability_stage() {
let mut loadout = Loadout::default(); let mut loadout = Loadout::default();
loadout.active_item = Some(ItemConfig { 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, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,
@ -143,7 +146,7 @@ fn ignores_different_ability_stage() {
let mut loadout = Loadout::default(); let mut loadout = Loadout::default();
loadout.active_item = Some(ItemConfig { 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, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,

View File

@ -97,7 +97,7 @@ impl ItemImgs {
pub fn new(ui: &mut Ui, not_found: Id) -> Self { pub fn new(ui: &mut Ui, not_found: Id) -> Self {
let mut indicator = ReloadIndicator::new(); let mut indicator = ReloadIndicator::new();
Self { Self {
map: assets::load_watched::<ItemImagesSpec>( map: ItemImagesSpec::load_watched(
"voxygen.item_image_manifest", "voxygen.item_image_manifest",
&mut indicator, &mut indicator,
) )
@ -118,7 +118,7 @@ impl ItemImgs {
/// Reuses img ids /// Reuses img ids
pub fn reload_if_changed(&mut self, ui: &mut Ui) { pub fn reload_if_changed(&mut self, ui: &mut Ui) {
if self.indicator.reloaded() { if self.indicator.reloaded() {
for (kind, spec) in assets::load::<ItemImagesSpec>("voxygen.item_image_manifest") for (kind, spec) in ItemImagesSpec::load("voxygen.item_image_manifest")
.expect("Unable to load item image manifest") .expect("Unable to load item image manifest")
.0 .0
.iter() .iter()
@ -160,21 +160,21 @@ impl ItemImgs {
// TODO: remove code dup? // TODO: remove code dup?
fn graceful_load_vox(specifier: &str) -> Arc<DotVoxData> { fn graceful_load_vox(specifier: &str) -> Arc<DotVoxData> {
let full_specifier: String = ["voxygen.", specifier].concat(); let full_specifier: String = ["voxygen.", specifier].concat();
match assets::load::<DotVoxData>(full_specifier.as_str()) { match DotVoxData::load(full_specifier.as_str()) {
Ok(dot_vox) => dot_vox, Ok(dot_vox) => dot_vox,
Err(_) => { Err(_) => {
error!(?full_specifier, "Could not load vox file for item images",); error!(?full_specifier, "Could not load vox file for item images",);
assets::load_expect::<DotVoxData>("voxygen.voxel.not_found") DotVoxData::load_expect("voxygen.voxel.not_found")
}, },
} }
} }
fn graceful_load_img(specifier: &str) -> Arc<DynamicImage> { fn graceful_load_img(specifier: &str) -> Arc<DynamicImage> {
let full_specifier: String = ["voxygen.", specifier].concat(); let full_specifier: String = ["voxygen.", specifier].concat();
match assets::load::<DynamicImage>(full_specifier.as_str()) { match DynamicImage::load(full_specifier.as_str()) {
Ok(img) => img, Ok(img) => img,
Err(_) => { Err(_) => {
error!(?full_specifier, "Could not load image file for item images"); error!(?full_specifier, "Could not load image file for item images");
assets::load_expect::<DynamicImage>("voxygen.element.not_found") DynamicImage::load_expect("voxygen.element.not_found")
}, },
} }
} }

View File

@ -56,7 +56,7 @@ use crate::{
GlobalState, GlobalState,
}; };
use client::Client; 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::{ use conrod_core::{
text::cursor::Index, text::cursor::Index,
widget::{self, Button, Image, Text}, widget::{self, Button, Image, Text},
@ -602,7 +602,7 @@ impl Hud {
// Load item images. // Load item images.
let item_imgs = ItemImgs::new(&mut ui, imgs.not_found); let item_imgs = ItemImgs::new(&mut ui, imgs.not_found);
// Load language. // Load language.
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key( let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
// Load fonts. // Load fonts.

View File

@ -1,7 +1,4 @@
use common::{ use common::assets::{self, Asset};
assets,
assets::{load_expect, load_glob, Asset},
};
use deunicode::deunicode; use deunicode::deunicode;
use ron::de::from_reader; use ron::de::from_reader;
use serde_derive::*; use serde_derive::*;
@ -100,7 +97,7 @@ impl VoxygenLocalization {
/// Return the missing keys compared to the reference language /// Return the missing keys compared to the reference language
pub fn list_missing_entries(&self) -> (HashSet<String>, HashSet<String>) { pub fn list_missing_entries(&self) -> (HashSet<String>, HashSet<String>) {
let reference_localization = let reference_localization =
load_expect::<VoxygenLocalization>(i18n_asset_key(REFERENCE_LANG).as_ref()); VoxygenLocalization::load_expect(i18n_asset_key(REFERENCE_LANG).as_ref());
let reference_string_keys: HashSet<_> = let reference_string_keys: HashSet<_> =
reference_localization.string_map.keys().cloned().collect(); 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 /// Load all the available languages located in the Voxygen asset directory
pub fn list_localizations() -> Vec<LanguageMetadata> { pub fn list_localizations() -> Vec<LanguageMetadata> {
let voxygen_locales_assets = "voxygen.i18n.*"; let voxygen_locales_assets = "voxygen.i18n.*";
let lang_list = load_glob::<VoxygenLocalization>(voxygen_locales_assets).unwrap(); let lang_list = VoxygenLocalization::load_glob(voxygen_locales_assets).unwrap();
lang_list.iter().map(|e| (*e).metadata.clone()).collect() lang_list.iter().map(|e| (*e).metadata.clone()).collect()
} }

View File

@ -15,7 +15,7 @@ use veloren_voxygen::{
}; };
use common::{ use common::{
assets::{load_watched, watch}, assets::{watch, Asset},
clock::Clock, clock::Clock,
}; };
use std::panic; use std::panic;
@ -132,7 +132,7 @@ fn main() {
let profile = Profile::load(); let profile = Profile::load();
let mut localization_watcher = watch::ReloadIndicator::new(); let mut localization_watcher = watch::ReloadIndicator::new();
let localized_strings = load_watched::<VoxygenLocalization>( let localized_strings = VoxygenLocalization::load_watched(
&i18n_asset_key(&settings.language.selected_language), &i18n_asset_key(&settings.language.selected_language),
&mut localization_watcher, &mut localization_watcher,
) )
@ -144,7 +144,7 @@ fn main() {
"Impossible to load language: change to the default language (English) instead.", "Impossible to load language: change to the default language (English) instead.",
); );
settings.language.selected_language = i18n::REFERENCE_LANG.to_owned(); settings.language.selected_language = i18n::REFERENCE_LANG.to_owned();
load_watched::<VoxygenLocalization>( VoxygenLocalization::load_watched(
&i18n_asset_key(&settings.language.selected_language), &i18n_asset_key(&settings.language.selected_language),
&mut localization_watcher, &mut localization_watcher,
) )

View File

@ -10,7 +10,7 @@ use crate::{
Direction, GlobalState, PlayState, PlayStateResult, Direction, GlobalState, PlayState, PlayStateResult,
}; };
use client::{self, Client}; 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 specs::WorldExt;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use tracing::error; use tracing::error;
@ -126,6 +126,7 @@ impl PlayState for CharSelectionState {
time: client.state().get_time(), time: client.state().get_time(),
delta_time: client.state().ecs().read_resource::<DeltaTime>().0, delta_time: client.state().ecs().read_resource::<DeltaTime>().0,
tick: client.get_tick(), tick: client.get_tick(),
thread_pool: client.thread_pool(),
body: humanoid_body, body: humanoid_body,
gamma: global_state.settings.graphics.gamma, gamma: global_state.settings.graphics.gamma,
mouse_smoothing: global_state.settings.gameplay.smooth_pan_enable, 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). // Tick the client (currently only to keep the connection alive).
let localized_strings = assets::load_expect::<VoxygenLocalization>(&i18n_asset_key( let localized_strings = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));

View File

@ -11,10 +11,9 @@ use crate::{
}; };
use client::Client; use client::Client;
use common::{ use common::{
assets, assets::Asset,
assets::load_expect,
character::{Character, CharacterItem, MAX_CHARACTERS_PER_PLAYER}, character::{Character, CharacterItem, MAX_CHARACTERS_PER_PLAYER},
comp::{self, humanoid}, comp::{self, humanoid, item::ItemAsset},
LoadoutBuilder, LoadoutBuilder,
}; };
use conrod_core::{ use conrod_core::{
@ -321,7 +320,7 @@ impl CharSelectionUi {
let imgs = Imgs::load(&mut ui).expect("Failed to load images!"); let imgs = Imgs::load(&mut ui).expect("Failed to load images!");
let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!"); let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load images!");
// Load language // Load language
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key( let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
// Load fonts. // Load fonts.
@ -378,20 +377,24 @@ impl CharSelectionUi {
}, },
Mode::Create { loadout, tool, .. } => { Mode::Create { loadout, tool, .. } => {
loadout.active_item = tool.map(|tool| comp::ItemConfig { loadout.active_item = tool.map(|tool| comp::ItemConfig {
item: (*load_expect::<comp::Item>(tool)).clone(), // FIXME: Error gracefully.
item: (*ItemAsset::load_expect(tool)).clone(),
ability1: None, ability1: None,
ability2: None, ability2: None,
ability3: None, ability3: None,
block_ability: None, block_ability: None,
dodge_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", "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", "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", "common.items.armor.starter.sandals_0",
)); ));
Some(loadout.clone()) Some(loadout.clone())

View File

@ -9,7 +9,7 @@ use crate::{
PlayStateResult, PlayStateResult,
}; };
use client_init::{ClientInit, Error as InitError, Msg as InitMsg}; 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 tracing::{error, warn};
use ui::{Event as MainMenuEvent, MainMenuUi}; use ui::{Event as MainMenuEvent, MainMenuUi};
@ -46,7 +46,7 @@ impl PlayState for MainMenuState {
} }
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult { fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
let localized_strings = load_expect::<crate::i18n::VoxygenLocalization>( let localized_strings = crate::i18n::VoxygenLocalization::load_expect(
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language), &crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
); );

View File

@ -9,7 +9,7 @@ use crate::{
}, },
GlobalState, GlobalState,
}; };
use common::assets::load_expect; use common::assets::Asset;
use conrod_core::{ use conrod_core::{
color, color,
color::TRANSPARENT, color::TRANSPARENT,
@ -17,6 +17,7 @@ use conrod_core::{
widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox}, widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox},
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
}; };
use image::DynamicImage;
use rand::{seq::SliceRandom, thread_rng, Rng}; use rand::{seq::SliceRandom, thread_rng, Rng};
use std::time::Duration; use std::time::Duration;
@ -205,12 +206,12 @@ impl<'a> MainMenuUi {
let imgs = Imgs::load(&mut ui).expect("Failed to load images"); let imgs = Imgs::load(&mut ui).expect("Failed to load images");
let rot_imgs = ImgsRot::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( 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, None,
)); ));
//let chosen_tip = *tips.choose(&mut rng).unwrap(); //let chosen_tip = *tips.choose(&mut rng).unwrap();
// Load language // Load language
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key( let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
// Load fonts. // Load fonts.

View File

@ -12,7 +12,7 @@ use super::{
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode,
ShadowMapMode, ShadowMode, WrapMode, ShadowMapMode, ShadowMode, WrapMode,
}; };
use common::assets::{self, watch::ReloadIndicator}; use common::assets::{self, watch::ReloadIndicator, Asset};
use core::convert::TryFrom; use core::convert::TryFrom;
use gfx::{ use gfx::{
self, self,
@ -21,6 +21,11 @@ use gfx::{
traits::{Device, Factory, FactoryExt}, traits::{Device, Factory, FactoryExt},
}; };
use glsl_include::Context as IncludeContext; use glsl_include::Context as IncludeContext;
use image::DynamicImage;
use std::{
fs::File,
io::{BufReader, Read},
};
use tracing::{error, warn}; use tracing::{error, warn};
use vek::*; use vek::*;
@ -87,6 +92,21 @@ pub type ColLightInfo = (
Vec2<u16>, Vec2<u16>,
); );
/// 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<File>) -> Result<String, assets::Error> {
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 /// A type that holds shadow map data. Since shadow mapping may not be
/// supported on all platforms, we try to keep it separate. /// supported on all platforms, we try to keep it separate.
pub struct ShadowMapRenderer { pub struct ShadowMapRenderer {
@ -240,7 +260,7 @@ impl Renderer {
let noise_tex = Texture::new( let noise_tex = Texture::new(
&mut factory, &mut factory,
&assets::load_expect("voxygen.texture.noise"), &DynamicImage::load_expect("voxygen.texture.noise"),
Some(gfx::texture::FilterMethod::Bilinear), Some(gfx::texture::FilterMethod::Bilinear),
Some(gfx::texture::WrapMode::Tile), Some(gfx::texture::WrapMode::Tile),
None, None,
@ -1654,32 +1674,19 @@ fn create_pipelines(
), ),
RenderError, RenderError,
> { > {
let constants = assets::load_watched::<String>( let constants =
"voxygen.shaders.include.constants", Glsl::load_watched("voxygen.shaders.include.constants", shader_reload_indicator).unwrap();
shader_reload_indicator,
)
.unwrap();
let globals = let globals =
assets::load_watched::<String>("voxygen.shaders.include.globals", shader_reload_indicator) Glsl::load_watched("voxygen.shaders.include.globals", shader_reload_indicator).unwrap();
.unwrap(); let sky = Glsl::load_watched("voxygen.shaders.include.sky", shader_reload_indicator).unwrap();
let sky =
assets::load_watched::<String>("voxygen.shaders.include.sky", shader_reload_indicator)
.unwrap();
let light = let light =
assets::load_watched::<String>("voxygen.shaders.include.light", shader_reload_indicator) Glsl::load_watched("voxygen.shaders.include.light", shader_reload_indicator).unwrap();
.unwrap(); let srgb = Glsl::load_watched("voxygen.shaders.include.srgb", shader_reload_indicator).unwrap();
let srgb =
assets::load_watched::<String>("voxygen.shaders.include.srgb", shader_reload_indicator)
.unwrap();
let random = let random =
assets::load_watched::<String>("voxygen.shaders.include.random", shader_reload_indicator) Glsl::load_watched("voxygen.shaders.include.random", shader_reload_indicator).unwrap();
.unwrap(); let lod = Glsl::load_watched("voxygen.shaders.include.lod", shader_reload_indicator).unwrap();
let lod =
assets::load_watched::<String>("voxygen.shaders.include.lod", shader_reload_indicator)
.unwrap();
let shadows = let shadows =
assets::load_watched::<String>("voxygen.shaders.include.shadows", shader_reload_indicator) Glsl::load_watched("voxygen.shaders.include.shadows", shader_reload_indicator).unwrap();
.unwrap();
// We dynamically add extra configuration settings to the constants file. // We dynamically add extra configuration settings to the constants file.
let constants = format!( let constants = format!(
@ -1716,7 +1723,7 @@ fn create_pipelines(
}, },
); );
let anti_alias = assets::load_watched::<String>( let anti_alias = Glsl::load_watched(
&["voxygen.shaders.antialias.", match mode.aa { &["voxygen.shaders.antialias.", match mode.aa {
AaMode::None | AaMode::SsaaX4 => "none", AaMode::None | AaMode::SsaaX4 => "none",
AaMode::Fxaa => "fxaa", AaMode::Fxaa => "fxaa",
@ -1729,7 +1736,7 @@ fn create_pipelines(
) )
.unwrap(); .unwrap();
let cloud = assets::load_watched::<String>( let cloud = Glsl::load_watched(
&["voxygen.shaders.include.cloud.", match mode.cloud { &["voxygen.shaders.include.cloud.", match mode.cloud {
CloudMode::None => "none", CloudMode::None => "none",
CloudMode::Regular => "regular", CloudMode::Regular => "regular",
@ -1752,28 +1759,27 @@ fn create_pipelines(
include_ctx.include("cloud.glsl", &cloud); include_ctx.include("cloud.glsl", &cloud);
let figure_vert = let figure_vert =
assets::load_watched::<String>("voxygen.shaders.figure-vert", shader_reload_indicator) Glsl::load_watched("voxygen.shaders.figure-vert", shader_reload_indicator).unwrap();
.unwrap();
let terrain_point_shadow_vert = assets::load_watched::<String>( let terrain_point_shadow_vert = Glsl::load_watched(
"voxygen.shaders.light-shadows-vert", "voxygen.shaders.light-shadows-vert",
shader_reload_indicator, shader_reload_indicator,
) )
.unwrap(); .unwrap();
let terrain_directed_shadow_vert = assets::load_watched::<String>( let terrain_directed_shadow_vert = Glsl::load_watched(
"voxygen.shaders.light-shadows-directed-vert", "voxygen.shaders.light-shadows-directed-vert",
shader_reload_indicator, shader_reload_indicator,
) )
.unwrap(); .unwrap();
let figure_directed_shadow_vert = assets::load_watched::<String>( let figure_directed_shadow_vert = Glsl::load_watched(
"voxygen.shaders.light-shadows-figure-vert", "voxygen.shaders.light-shadows-figure-vert",
shader_reload_indicator, shader_reload_indicator,
) )
.unwrap(); .unwrap();
let directed_shadow_frag = &assets::load_watched::<String>( let directed_shadow_frag = Glsl::load_watched(
"voxygen.shaders.light-shadows-directed-frag", "voxygen.shaders.light-shadows-directed-frag",
shader_reload_indicator, shader_reload_indicator,
) )
@ -1783,10 +1789,8 @@ fn create_pipelines(
let skybox_pipeline = create_pipeline( let skybox_pipeline = create_pipeline(
factory, factory,
skybox::pipe::new(), skybox::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.skybox-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.skybox-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched("voxygen.shaders.skybox-frag", shader_reload_indicator).unwrap(),
&assets::load_watched::<String>("voxygen.shaders.skybox-frag", shader_reload_indicator)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1796,8 +1800,7 @@ fn create_pipelines(
factory, factory,
figure::pipe::new(), figure::pipe::new(),
&figure_vert, &figure_vert,
&assets::load_watched::<String>("voxygen.shaders.figure-frag", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.figure-frag", shader_reload_indicator).unwrap(),
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1806,10 +1809,8 @@ fn create_pipelines(
let terrain_pipeline = create_pipeline( let terrain_pipeline = create_pipeline(
factory, factory,
terrain::pipe::new(), terrain::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.terrain-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.terrain-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched("voxygen.shaders.terrain-frag", shader_reload_indicator).unwrap(),
&assets::load_watched::<String>("voxygen.shaders.terrain-frag", shader_reload_indicator)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1818,9 +1819,8 @@ fn create_pipelines(
let fluid_pipeline = create_pipeline( let fluid_pipeline = create_pipeline(
factory, factory,
fluid::pipe::new(), fluid::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.fluid-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.fluid-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched(
&assets::load_watched::<String>(
&["voxygen.shaders.fluid-frag.", match mode.fluid { &["voxygen.shaders.fluid-frag.", match mode.fluid {
FluidMode::Cheap => "cheap", FluidMode::Cheap => "cheap",
FluidMode::Shiny => "shiny", FluidMode::Shiny => "shiny",
@ -1837,10 +1837,8 @@ fn create_pipelines(
let sprite_pipeline = create_pipeline( let sprite_pipeline = create_pipeline(
factory, factory,
sprite::pipe::new(), sprite::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.sprite-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.sprite-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched("voxygen.shaders.sprite-frag", shader_reload_indicator).unwrap(),
&assets::load_watched::<String>("voxygen.shaders.sprite-frag", shader_reload_indicator)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1849,10 +1847,8 @@ fn create_pipelines(
let particle_pipeline = create_pipeline( let particle_pipeline = create_pipeline(
factory, factory,
particle::pipe::new(), particle::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.particle-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.particle-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched("voxygen.shaders.particle-frag", shader_reload_indicator).unwrap(),
&assets::load_watched::<String>("voxygen.shaders.particle-frag", shader_reload_indicator)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1861,10 +1857,8 @@ fn create_pipelines(
let ui_pipeline = create_pipeline( let ui_pipeline = create_pipeline(
factory, factory,
ui::pipe::new(), ui::pipe::new(),
&assets::load_watched::<String>("voxygen.shaders.ui-vert", shader_reload_indicator) &Glsl::load_watched("voxygen.shaders.ui-vert", shader_reload_indicator).unwrap(),
.unwrap(), &Glsl::load_watched("voxygen.shaders.ui-frag", shader_reload_indicator).unwrap(),
&assets::load_watched::<String>("voxygen.shaders.ui-frag", shader_reload_indicator)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1873,16 +1867,8 @@ fn create_pipelines(
let lod_terrain_pipeline = create_pipeline( let lod_terrain_pipeline = create_pipeline(
factory, factory,
lod_terrain::pipe::new(), lod_terrain::pipe::new(),
&assets::load_watched::<String>( &Glsl::load_watched("voxygen.shaders.lod-terrain-vert", shader_reload_indicator).unwrap(),
"voxygen.shaders.lod-terrain-vert", &Glsl::load_watched("voxygen.shaders.lod-terrain-frag", shader_reload_indicator).unwrap(),
shader_reload_indicator,
)
.unwrap(),
&assets::load_watched::<String>(
"voxygen.shaders.lod-terrain-frag",
shader_reload_indicator,
)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1891,16 +1877,8 @@ fn create_pipelines(
let postprocess_pipeline = create_pipeline( let postprocess_pipeline = create_pipeline(
factory, factory,
postprocess::pipe::new(), postprocess::pipe::new(),
&assets::load_watched::<String>( &Glsl::load_watched("voxygen.shaders.postprocess-vert", shader_reload_indicator).unwrap(),
"voxygen.shaders.postprocess-vert", &Glsl::load_watched("voxygen.shaders.postprocess-frag", shader_reload_indicator).unwrap(),
shader_reload_indicator,
)
.unwrap(),
&assets::load_watched::<String>(
"voxygen.shaders.postprocess-frag",
shader_reload_indicator,
)
.unwrap(),
&include_ctx, &include_ctx,
gfx::state::CullFace::Back, gfx::state::CullFace::Back,
)?; )?;
@ -1918,7 +1896,7 @@ fn create_pipelines(
..figure::pipe::new() ..figure::pipe::new()
}, },
&figure_vert, &figure_vert,
&assets::load_watched::<String>( &Glsl::load_watched(
"voxygen.shaders.player-shadow-frag", "voxygen.shaders.player-shadow-frag",
shader_reload_indicator, shader_reload_indicator,
) )
@ -1933,13 +1911,13 @@ fn create_pipelines(
shadow::pipe::new(), shadow::pipe::new(),
&terrain_point_shadow_vert, &terrain_point_shadow_vert,
Some( Some(
&assets::load_watched::<String>( &Glsl::load_watched(
"voxygen.shaders.light-shadows-geom", "voxygen.shaders.light-shadows-geom",
shader_reload_indicator, shader_reload_indicator,
) )
.unwrap(), .unwrap(),
), ),
&assets::load_watched::<String>( &Glsl::load_watched(
"voxygen.shaders.light-shadows-frag", "voxygen.shaders.light-shadows-frag",
shader_reload_indicator, shader_reload_indicator,
) )

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,9 @@ pub use load::load_mesh; // TODO: Don't make this public.
use crate::{ use crate::{
ecs::comp::Interpolated, ecs::comp::Interpolated,
mesh::greedy::GreedyMesh,
render::{ render::{
ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel, Mesh, ColLightFmt, ColLightInfo, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel,
RenderError, Renderer, ShadowPipeline, TerrainPipeline, Texture, Mesh, RenderError, Renderer, ShadowPipeline, TerrainPipeline, Texture,
}, },
scene::{ scene::{
camera::{Camera, CameraMode, Dependents}, camera::{Camera, CameraMode, Dependents},
@ -308,6 +307,7 @@ pub struct FigureMgr {
fish_medium_model_cache: FigureModelCache<FishMediumSkeleton>, fish_medium_model_cache: FigureModelCache<FishMediumSkeleton>,
fish_small_model_cache: FigureModelCache<FishSmallSkeleton>, fish_small_model_cache: FigureModelCache<FishSmallSkeleton>,
biped_large_model_cache: FigureModelCache<BipedLargeSkeleton>, biped_large_model_cache: FigureModelCache<BipedLargeSkeleton>,
object_model_cache: FigureModelCache<ObjectSkeleton>,
golem_model_cache: FigureModelCache<GolemSkeleton>, golem_model_cache: FigureModelCache<GolemSkeleton>,
states: FigureMgrStates, states: FigureMgrStates,
} }
@ -327,6 +327,7 @@ impl FigureMgr {
fish_medium_model_cache: FigureModelCache::new(), fish_medium_model_cache: FigureModelCache::new(),
fish_small_model_cache: FigureModelCache::new(), fish_small_model_cache: FigureModelCache::new(),
biped_large_model_cache: FigureModelCache::new(), biped_large_model_cache: FigureModelCache::new(),
object_model_cache: FigureModelCache::new(),
golem_model_cache: FigureModelCache::new(), golem_model_cache: FigureModelCache::new(),
states: FigureMgrStates::default(), states: FigureMgrStates::default(),
} }
@ -354,6 +355,7 @@ impl FigureMgr {
.clean(&mut self.col_lights, tick); .clean(&mut self.col_lights, tick);
self.biped_large_model_cache self.biped_large_model_cache
.clean(&mut self.col_lights, tick); .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); self.golem_model_cache.clean(&mut self.col_lights, tick);
} }
@ -685,7 +687,7 @@ impl FigureMgr {
}; };
match body { match body {
Body::Humanoid(_) => { Body::Humanoid(body) => {
let (model, skeleton_attr) = self.model_cache.get_or_create_model( let (model, skeleton_attr) = self.model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -694,6 +696,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1046,7 +1049,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1054,7 +1057,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::QuadrupedSmall(_) => { Body::QuadrupedSmall(body) => {
let (model, skeleton_attr) = let (model, skeleton_attr) =
self.quadruped_small_model_cache.get_or_create_model( self.quadruped_small_model_cache.get_or_create_model(
renderer, renderer,
@ -1064,6 +1067,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1147,7 +1151,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1155,7 +1159,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::QuadrupedMedium(_) => { Body::QuadrupedMedium(body) => {
let (model, skeleton_attr) = let (model, skeleton_attr) =
self.quadruped_medium_model_cache.get_or_create_model( self.quadruped_medium_model_cache.get_or_create_model(
renderer, renderer,
@ -1165,6 +1169,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1248,7 +1253,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1256,7 +1261,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::QuadrupedLow(_) => { Body::QuadrupedLow(body) => {
let (model, skeleton_attr) = let (model, skeleton_attr) =
self.quadruped_low_model_cache.get_or_create_model( self.quadruped_low_model_cache.get_or_create_model(
renderer, renderer,
@ -1266,6 +1271,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1347,7 +1353,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1355,7 +1361,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::BirdMedium(_) => { Body::BirdMedium(body) => {
let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model( let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1364,6 +1370,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1443,7 +1450,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1451,7 +1458,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::FishMedium(_) => { Body::FishMedium(body) => {
let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model( let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1460,6 +1467,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1528,7 +1536,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1536,7 +1544,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::Dragon(_) => { Body::Dragon(body) => {
let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model( let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1545,6 +1553,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = let state =
@ -1609,7 +1618,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1617,7 +1626,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::Critter(_) => { Body::Critter(body) => {
let (model, skeleton_attr) = self.critter_model_cache.get_or_create_model( let (model, skeleton_attr) = self.critter_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1626,6 +1635,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = let state =
@ -1691,7 +1701,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1699,7 +1709,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::BirdSmall(_) => { Body::BirdSmall(body) => {
let (model, skeleton_attr) = self.bird_small_model_cache.get_or_create_model( let (model, skeleton_attr) = self.bird_small_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1708,6 +1718,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1776,7 +1787,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1784,7 +1795,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::FishSmall(_) => { Body::FishSmall(body) => {
let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model( let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1793,6 +1804,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1861,7 +1873,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1869,7 +1881,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::BipedLarge(_) => { Body::BipedLarge(body) => {
let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model( let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1878,6 +1890,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = self let state = self
@ -1966,7 +1979,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -1974,7 +1987,7 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::Golem(_) => { Body::Golem(body) => {
let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model( let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
@ -1983,6 +1996,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = let state =
@ -2048,7 +2062,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
in_frustum, in_frustum,
is_player, is_player,
@ -2056,8 +2070,8 @@ impl FigureMgr {
&mut update_buf, &mut update_buf,
); );
}, },
Body::Object(_) => { Body::Object(body) => {
let (model, _) = &self.model_cache.get_or_create_model( let (model, _) = self.object_model_cache.get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
*body, *body,
@ -2065,6 +2079,7 @@ impl FigureMgr {
tick, tick,
player_camera_mode, player_camera_mode,
player_character_state, player_character_state,
scene_data.thread_pool,
); );
let state = let state =
@ -2080,7 +2095,7 @@ impl FigureMgr {
col, col,
dt, dt,
state_animation_rate, state_animation_rate,
&model, model,
lpindex, lpindex,
true, true,
is_player, is_player,
@ -2102,7 +2117,7 @@ impl FigureMgr {
} }
pub fn render_shadows( pub fn render_shadows(
&mut self, &self,
renderer: &mut Renderer, renderer: &mut Renderer,
state: &State, state: &State,
tick: u64, tick: u64,
@ -2127,7 +2142,6 @@ impl FigureMgr {
.filter(|(_, _, _, _, stats, _, _)| stats.map_or(true, |s| !s.is_dead)) .filter(|(_, _, _, _, stats, _, _)| stats.map_or(true, |s| !s.is_dead))
.for_each(|(entity, pos, _, body, _, loadout, _)| { .for_each(|(entity, pos, _, body, _, loadout, _)| {
if let Some((locals, bone_consts, model, _)) = self.get_model_for_render( if let Some((locals, bone_consts, model, _)) = self.get_model_for_render(
renderer,
tick, tick,
camera, camera,
None, None,
@ -2153,7 +2167,7 @@ impl FigureMgr {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn render( pub fn render(
&mut self, &self,
renderer: &mut Renderer, renderer: &mut Renderer,
state: &State, state: &State,
player_entity: EcsEntity, player_entity: EcsEntity,
@ -2184,7 +2198,6 @@ impl FigureMgr {
if !is_player { if !is_player {
if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render(
renderer,
tick, tick,
camera, camera,
character_state, character_state,
@ -2204,7 +2217,7 @@ impl FigureMgr {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn render_player( pub fn render_player(
&mut self, &self,
renderer: &mut Renderer, renderer: &mut Renderer,
state: &State, state: &State,
player_entity: EcsEntity, player_entity: EcsEntity,
@ -2233,7 +2246,6 @@ impl FigureMgr {
let loadout = loadout_storage.get(player_entity); let loadout = loadout_storage.get(player_entity);
if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render(
renderer,
tick, tick,
camera, camera,
character_state, character_state,
@ -2260,8 +2272,7 @@ impl FigureMgr {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
fn get_model_for_render( fn get_model_for_render(
&mut self, &self,
renderer: &mut Renderer,
tick: u64, tick: u64,
camera: &Camera, camera: &Camera,
character_state: Option<&CharacterState>, character_state: Option<&CharacterState>,
@ -2283,7 +2294,7 @@ impl FigureMgr {
let character_state = if is_player { character_state } else { None }; let character_state = if is_player { character_state } else { None };
let FigureMgr { let FigureMgr {
col_lights: ref mut col_lights_, col_lights: ref col_lights_,
model_cache, model_cache,
critter_model_cache, critter_model_cache,
quadruped_small_model_cache, quadruped_small_model_cache,
@ -2295,6 +2306,7 @@ impl FigureMgr {
fish_medium_model_cache, fish_medium_model_cache,
fish_small_model_cache, fish_small_model_cache,
biped_large_model_cache, biped_large_model_cache,
object_model_cache,
golem_model_cache, golem_model_cache,
states: states:
FigureMgrStates { FigureMgrStates {
@ -2313,269 +2325,232 @@ impl FigureMgr {
object_states, object_states,
}, },
} = self; } = self;
let col_lights = &mut *col_lights_; let col_lights = &*col_lights_;
if let Some((locals, bone_consts, model_entry)) = match body { if let Some((locals, bone_consts, model_entry)) = match body {
Body::Humanoid(_) => character_states Body::Humanoid(body) => character_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&model_cache model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::QuadrupedSmall(_) => quadruped_small_states Body::QuadrupedSmall(body) => quadruped_small_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&quadruped_small_model_cache quadruped_small_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::QuadrupedMedium(_) => quadruped_medium_states Body::QuadrupedMedium(body) => quadruped_medium_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&quadruped_medium_model_cache quadruped_medium_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::QuadrupedLow(_) => quadruped_low_states Body::QuadrupedLow(body) => quadruped_low_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&quadruped_low_model_cache quadruped_low_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::BirdMedium(_) => bird_medium_states Body::BirdMedium(body) => bird_medium_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&bird_medium_model_cache bird_medium_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::FishMedium(_) => fish_medium_states Body::FishMedium(body) => fish_medium_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&fish_medium_model_cache fish_medium_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::Critter(_) => critter_states Body::Critter(body) => critter_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&critter_model_cache critter_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::Dragon(_) => dragon_states Body::Dragon(body) => dragon_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&dragon_model_cache dragon_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::BirdSmall(_) => bird_small_states Body::BirdSmall(body) => bird_small_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&bird_small_model_cache bird_small_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::FishSmall(_) => fish_small_states Body::FishSmall(body) => fish_small_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&fish_small_model_cache fish_small_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::BipedLarge(_) => biped_large_states Body::BipedLarge(body) => biped_large_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&biped_large_model_cache biped_large_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::Golem(_) => golem_states Body::Golem(body) => golem_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&golem_model_cache golem_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
Body::Object(_) => object_states Body::Object(body) => object_states
.get(&entity) .get(&entity)
.filter(|state| filter_state(&*state)) .filter(|state| filter_state(&*state))
.map(move |state| { .map(move |state| {
( (
state.locals(), state.locals(),
state.bone_consts(), state.bone_consts(),
&model_cache object_model_cache.get_model(
.get_or_create_model( col_lights,
renderer, *body,
col_lights, loadout,
*body, tick,
loadout, player_camera_mode,
tick, character_state,
player_camera_mode, ),
character_state,
)
.0,
) )
}), }),
} { } {
let model_entry = model_entry?;
let figure_low_detail_distance = figure_lod_render_distance * 0.75; let figure_low_detail_distance = figure_lod_render_distance * 0.75;
let figure_mid_detail_distance = figure_lod_render_distance * 0.5; 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 /// 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 /// model stored in the BoneMeshes parameter. This is part of the
/// function contract. /// function contract.
pub fn create_figure<'a, const N: usize>( pub fn create_figure<const N: usize>(
&mut self, &mut self,
renderer: &mut Renderer, renderer: &mut Renderer,
greedy: GreedyMesh<'a>, (tex, tex_size): ColLightInfo,
(opaque, bounds): (Mesh<TerrainPipeline>, math::Aabb<f32>), (opaque, bounds): (Mesh<TerrainPipeline>, math::Aabb<f32>),
vertex_range: [Range<u32>; N], vertex_range: [Range<u32>; N],
) -> Result<FigureModelEntry<N>, RenderError> { ) -> Result<FigureModelEntry<N>, RenderError> {
let (tex, tex_size) = greedy.finalize();
let atlas = &mut self.atlas; let atlas = &mut self.atlas;
let allocation = atlas let allocation = atlas
.allocate(guillotiere::Size::new( .allocate(guillotiere::Size::new(
@ -2771,14 +2745,31 @@ impl<S: Skeleton> FigureState<S> {
col: vek::Rgba<f32>, col: vek::Rgba<f32>,
dt: f32, dt: f32,
state_animation_rate: f32, state_animation_rate: f32,
model: &FigureModelEntry<N>, model: Option<&FigureModelEntry<N>>,
_lpindex: u8, _lpindex: u8,
_visible: bool, _visible: bool,
is_player: bool, is_player: bool,
camera: &Camera, _camera: &Camera,
buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT], 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 // Approximate as a sphere with radius equal to the
// largest dimension (if we were exact, it should just be half the largest // largest dimension (if we were exact, it should just be half the largest

View File

@ -7,7 +7,7 @@ use crate::{
}, },
}; };
use common::{ use common::{
assets, assets::Asset,
comp::{item::Reagent, object, Body, CharacterState, Pos}, comp::{item::Reagent, object, Body, CharacterState, Pos},
figure::Segment, figure::Segment,
outcome::Outcome, outcome::Outcome,
@ -369,7 +369,7 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model<Particl
let mut model_cache = HashMap::new(); let mut model_cache = HashMap::new();
model_cache.entry(DEFAULT_MODEL_KEY).or_insert_with(|| { model_cache.entry(DEFAULT_MODEL_KEY).or_insert_with(|| {
let vox = assets::load_expect::<DotVoxData>(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 // NOTE: If we add texturing we may eventually try to share it among all
// particles in a single atlas. // particles in a single atlas.

View File

@ -19,7 +19,7 @@ use anim::{
}; };
use client::Client; use client::Client;
use common::{ use common::{
comp::{humanoid, item::ItemKind, Body, Loadout}, comp::{humanoid, item::ItemKind, Loadout},
figure::Segment, figure::Segment,
terrain::BlockKind, terrain::BlockKind,
vol::{BaseVol, ReadVol, Vox}, vol::{BaseVol, ReadVol, Vox},
@ -87,10 +87,11 @@ pub struct Scene {
char_ori: f32, char_ori: f32,
} }
pub struct SceneData { pub struct SceneData<'a> {
pub time: f64, pub time: f64,
pub delta_time: f32, pub delta_time: f32,
pub tick: u64, pub tick: u64,
pub thread_pool: &'a uvth::ThreadPool,
pub body: Option<humanoid::Body>, pub body: Option<humanoid::Body>,
pub gamma: f32, pub gamma: f32,
pub figure_lod_render_distance: f32, pub figure_lod_render_distance: f32,
@ -164,7 +165,7 @@ impl Scene {
// 2^27, which fits in a u32. // 2^27, which fits in a u32.
let range = range.start as u32..range.end as u32; let range = range.start as u32..range.end as u32;
let model = col_lights let model = col_lights
.create_figure(renderer, greedy, (opaque_mesh, bounds), [range]) .create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range])
.unwrap(); .unwrap();
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
state.update( state.update(
@ -175,7 +176,7 @@ impl Scene {
Rgba::broadcast(1.0), Rgba::broadcast(1.0),
15.0, // Want to get there immediately. 15.0, // Want to get there immediately.
1.0, 1.0,
&model, Some(&model),
0, 0,
true, true,
false, false,
@ -304,16 +305,17 @@ impl Scene {
*self.figure_state.skeleton_mut() = *self.figure_state.skeleton_mut() =
anim::vek::Lerp::lerp(&*self.figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp); anim::vek::Lerp::lerp(&*self.figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
let model = &self let model = self
.figure_model_cache .figure_model_cache
.get_or_create_model( .get_or_create_model(
renderer, renderer,
&mut self.col_lights, &mut self.col_lights,
Body::Humanoid(body), body,
loadout, loadout,
scene_data.tick, scene_data.tick,
CameraMode::default(), CameraMode::default(),
None, None,
scene_data.thread_pool,
) )
.0; .0;
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
@ -325,7 +327,7 @@ impl Scene {
Rgba::broadcast(1.0), Rgba::broadcast(1.0),
scene_data.delta_time, scene_data.delta_time,
1.0, 1.0,
&model, model,
0, 0,
true, true,
false, false,
@ -350,27 +352,25 @@ impl Scene {
); );
if let Some(body) = body { if let Some(body) = body {
let model = &self let model = &self.figure_model_cache.get_model(
.figure_model_cache &self.col_lights,
.get_or_create_model( body,
renderer, loadout,
&mut self.col_lights, tick,
Body::Humanoid(body), CameraMode::default(),
loadout, None,
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,
); );
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 { if let Some((model, state)) = &self.backdrop {

View File

@ -13,7 +13,7 @@ use crate::{
use super::{math, LodData, SceneData}; use super::{math, LodData, SceneData};
use common::{ use common::{
assets, assets::Asset,
figure::Segment, figure::Segment,
spiral::Spiral2d, spiral::Spiral2d,
terrain::{Block, BlockKind, TerrainChunk}, terrain::{Block, BlockKind, TerrainChunk},
@ -25,6 +25,7 @@ use crossbeam::channel;
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use guillotiere::AtlasAllocator; use guillotiere::AtlasAllocator;
use hashbrown::HashMap; use hashbrown::HashMap;
use image::DynamicImage;
use std::sync::Arc; use std::sync::Arc;
use tracing::warn; use tracing::warn;
use treeculler::{BVol, Frustum, AABB}; use treeculler::{BVol, Frustum, AABB};
@ -525,7 +526,7 @@ impl<V: RectRasterableVol> Terrain<V> {
// NOTE: Tracks the start vertex of the next model to be meshed. // NOTE: Tracks the start vertex of the next model to be meshed.
let mut make_models = |(kind, variation), s, offset, lod_axes: Vec3<f32>| { let mut make_models = |(kind, variation), s, offset, lod_axes: Vec3<f32>| {
let scaled = [1.0, 0.8, 0.6, 0.4, 0.2]; let scaled = [1.0, 0.8, 0.6, 0.4, 0.2];
let model = assets::load_expect::<DotVoxData>(s); let model = DotVoxData::load_expect(s);
let zero = Vec3::zero(); let zero = Vec3::zero();
let model_size = model let model_size = model
.models .models
@ -2401,7 +2402,7 @@ impl<V: RectRasterableVol> Terrain<V> {
sprite_col_lights, sprite_col_lights,
waves: renderer waves: renderer
.create_texture( .create_texture(
&assets::load_expect("voxygen.texture.waves"), &DynamicImage::load_expect("voxygen.texture.waves"),
Some(gfx::texture::FilterMethod::Trilinear), Some(gfx::texture::FilterMethod::Trilinear),
Some(gfx::texture::WrapMode::Tile), Some(gfx::texture::WrapMode::Tile),
None, None,

View File

@ -13,7 +13,7 @@ use crate::{
}; };
use client::{self, Client}; use client::{self, Client};
use common::{ use common::{
assets::{load_expect, load_watched}, assets::Asset,
comp, comp,
comp::{ comp::{
ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR, ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR,
@ -72,7 +72,7 @@ impl SessionState {
.camera_mut() .camera_mut()
.set_fov_deg(global_state.settings.graphics.fov); .set_fov_deg(global_state.settings.graphics.fov);
let hud = Hud::new(global_state, &client.borrow()); let hud = Hud::new(global_state, &client.borrow());
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key( let voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
@ -196,7 +196,7 @@ impl PlayState for SessionState {
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult { fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
// NOTE: Not strictly necessary, but useful for hotloading translation changes. // NOTE: Not strictly necessary, but useful for hotloading translation changes.
self.voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key( self.voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
@ -991,7 +991,7 @@ impl PlayState for SessionState {
HudEvent::ChangeLanguage(new_language) => { HudEvent::ChangeLanguage(new_language) => {
global_state.settings.language.selected_language = global_state.settings.language.selected_language =
new_language.language_identifier; new_language.language_identifier;
self.voxygen_i18n = load_watched::<VoxygenLocalization>( self.voxygen_i18n = VoxygenLocalization::load_watched(
&i18n_asset_key(&global_state.settings.language.selected_language), &i18n_asset_key(&global_state.settings.language.selected_language),
&mut global_state.localization_watcher, &mut global_state.localization_watcher,
) )

View File

@ -1,4 +1,5 @@
use crate::i18n::{Font, VoxygenFonts}; use crate::i18n::{Font, VoxygenFonts};
use common::assets::Asset;
pub struct ConrodVoxygenFont { pub struct ConrodVoxygenFont {
metadata: Font, metadata: Font,
@ -10,7 +11,7 @@ impl ConrodVoxygenFont {
pub fn new(font: &Font, ui: &mut crate::ui::Ui) -> ConrodVoxygenFont { pub fn new(font: &Font, ui: &mut crate::ui::Ui) -> ConrodVoxygenFont {
return Self { return Self {
metadata: font.clone(), 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)),
}; };
} }

View File

@ -1,6 +1,6 @@
use super::{Graphic, SampleStrat, Transform}; use super::{Graphic, SampleStrat, Transform};
use common::{ use common::{
assets::{load, Error}, assets::{Asset, Error},
figure::Segment, figure::Segment,
}; };
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
@ -24,7 +24,7 @@ impl<'a> GraphicCreator<'a> for ImageGraphic {
type Specifier = &'a str; type Specifier = &'a str;
fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> { fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> {
Ok(Graphic::Image(load::<DynamicImage>(specifier)?, None)) Ok(Graphic::Image(DynamicImage::load(specifier)?, None))
} }
} }
@ -37,7 +37,7 @@ pub enum VoxelSs9Graphic {}
pub enum VoxelPixArtGraphic {} pub enum VoxelPixArtGraphic {}
fn load_segment(specifier: &str) -> Result<Arc<Segment>, Error> { fn load_segment(specifier: &str) -> Result<Arc<Segment>, Error> {
let dot_vox = load::<DotVoxData>(specifier)?; let dot_vox = DotVoxData::load(specifier)?;
let seg = dot_vox.as_ref().into(); let seg = dot_vox.as_ref().into();
Ok(Arc::new(seg)) Ok(Arc::new(seg))
} }

View File

@ -13,10 +13,10 @@ use common::{
vol::{ReadVol, Vox}, vol::{ReadVol, Vox},
}; };
use core::ops::{Div, Mul, Range}; use core::ops::{Div, Mul, Range};
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub pyramid: (u8, u8, u8), pub pyramid: (u8, u8, u8),
// TODO(@Sharp): After the merge, construct enough infrastructure to make it convenient to // TODO(@Sharp): After the merge, construct enough infrastructure to make it convenient to

View File

@ -13,7 +13,7 @@ use common::{
vol::RectVolSize, vol::RectVolSize,
}; };
use noise::NoiseFn; use noise::NoiseFn;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::{ use std::{
cmp::Reverse, cmp::Reverse,
f32, f64, f32, f64,
@ -26,7 +26,7 @@ pub struct ColumnGen<'a> {
pub sim: &'a WorldSim, pub sim: &'a WorldSim,
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub cold_grass: (f32, f32, f32), pub cold_grass: (f32, f32, f32),
pub warm_grass: (f32, f32, f32), pub warm_grass: (f32, f32, f32),

View File

@ -1,6 +1,6 @@
use crate::{site::Site, Colors}; use crate::{site::Site, Colors};
use common::{ use common::{
assets::{self, watch::ReloadIndicator}, assets::{watch::ReloadIndicator, Asset, Ron},
store::Store, store::Store,
}; };
use core::ops::Deref; use core::ops::Deref;
@ -53,7 +53,7 @@ impl Index {
/// NOTE: Panics if the color manifest cannot be loaded. /// NOTE: Panics if the color manifest cannot be loaded.
pub fn new(seed: u32) -> (Self, Arc<Colors>) { pub fn new(seed: u32) -> (Self, Arc<Colors>) {
let mut indicator = ReloadIndicator::new(); let mut indicator = ReloadIndicator::new();
let colors = assets::load_watched::<Colors>(WORLD_COLORS_MANIFEST, &mut indicator) let colors = Ron::<Colors>::load_watched(WORLD_COLORS_MANIFEST, &mut indicator)
.expect("Could not load world colors!"); .expect("Could not load world colors!");
( (
@ -90,7 +90,7 @@ impl IndexOwned {
) -> Option<R> { ) -> Option<R> {
self.indicator.reloaded().then(move || { self.indicator.reloaded().then(move || {
// We know the asset was loaded before, so load_expect should be fine. // We know the asset was loaded before, so load_expect should be fine.
self.colors = assets::load_expect::<Colors>(WORLD_COLORS_MANIFEST); self.colors = Ron::<Colors>::load_expect(WORLD_COLORS_MANIFEST);
reload(self) reload(self)
}) })
} }

View File

@ -5,7 +5,8 @@ use crate::{
IndexRef, CONFIG, IndexRef, CONFIG,
}; };
use common::{ use common::{
assets, comp, assets::Asset,
comp,
generation::{ChunkSupplement, EntityInfo}, generation::{ChunkSupplement, EntityInfo},
lottery::Lottery, lottery::Lottery,
terrain::{Block, BlockKind}, terrain::{Block, BlockKind},
@ -13,14 +14,14 @@ use common::{
}; };
use noise::NoiseFn; use noise::NoiseFn;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::{ use std::{
f32, f32,
ops::{Mul, Sub}, ops::{Mul, Sub},
}; };
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub bridge: (u8, u8, u8), pub bridge: (u8, u8, u8),
pub stalagtite: (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)) if RandomField::new(index.seed).chance(wpos2d.into(), 0.001 * difficulty.powf(1.5))
&& cave_base < surface_z as i32 - 25 && cave_base < surface_z as i32 - 25
{ {
let kind = *assets::load_expect::<Lottery<BlockKind>>("common.cave_scatter") let kind = *Lottery::<BlockKind>::load_expect("common.cave_scatter")
.choose_seeded(RandomField::new(index.seed + 1).get(wpos2d.into())); .choose_seeded(RandomField::new(index.seed + 1).get(wpos2d.into()));
let _ = vol.set( let _ = vol.set(
Vec3::new(offs.x, offs.y, cave_base), Vec3::new(offs.x, offs.y, cave_base),

View File

@ -34,7 +34,6 @@ use crate::{
util::{Grid, Sampler}, util::{Grid, Sampler},
}; };
use common::{ use common::{
assets::{self, Asset},
comp::{self, bird_medium, critter, quadruped_low, quadruped_medium, quadruped_small}, comp::{self, bird_medium, critter, quadruped_low, quadruped_medium, quadruped_small},
generation::{ChunkSupplement, EntityInfo}, generation::{ChunkSupplement, EntityInfo},
msg::server::WorldMapMsg, msg::server::WorldMapMsg,
@ -42,8 +41,8 @@ use common::{
vol::{ReadVol, RectVolSize, Vox, WriteVol}, vol::{ReadVol, RectVolSize, Vox, WriteVol},
}; };
use rand::Rng; use rand::Rng;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::{fs::File, io::BufReader, time::Duration}; use std::time::Duration;
use vek::*; use vek::*;
#[derive(Debug)] #[derive(Debug)]
@ -56,7 +55,7 @@ pub struct World {
civs: civ::Civs, civs: civ::Civs,
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub deep_stone_color: (u8, u8, u8), pub deep_stone_color: (u8, u8, u8),
pub block: block::Colors, pub block: block::Colors,
@ -65,14 +64,6 @@ pub struct Colors {
pub site: site::Colors, pub site: site::Colors,
} }
impl Asset for Colors {
const ENDINGS: &'static [&'static str] = &["ron"];
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error)
}
}
impl World { impl World {
pub fn generate(seed: u32, opts: sim::WorldOpts) -> (Self, IndexOwned) { pub fn generate(seed: u32, opts: sim::WorldOpts) -> (Self, IndexOwned) {
// NOTE: Generating index first in order to quickly fail if the color manifest // NOTE: Generating index first in order to quickly fail if the color manifest

View File

@ -15,7 +15,7 @@ use common::{
}; };
use core::f32; use core::f32;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
struct Keep { struct Keep {
@ -49,7 +49,7 @@ pub struct GenCtx<'a, R: Rng> {
rng: &'a mut R, rng: &'a mut R,
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors; pub struct Colors;
impl Castle { impl Castle {

View File

@ -8,9 +8,9 @@ use crate::{
IndexRef, IndexRef,
}; };
use common::{ use common::{
assets, assets::Asset,
astar::Astar, astar::Astar,
comp, comp::{self, item::ItemAsset},
generation::{ChunkSupplement, EntityInfo}, generation::{ChunkSupplement, EntityInfo},
lottery::Lottery, lottery::Lottery,
npc, npc,
@ -22,7 +22,7 @@ use core::{f32, hash::BuildHasherDefault};
use fxhash::FxHasher64; use fxhash::FxHasher64;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
@ -40,7 +40,7 @@ pub struct GenCtx<'a, R: Rng> {
rng: &'a mut R, rng: &'a mut R,
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub stone: (u8, u8, u8), pub stone: (u8, u8, u8),
} }
@ -461,12 +461,11 @@ impl Floor {
&& !tile_is_pillar && !tile_is_pillar
{ {
// Bad // Bad
let chosen = let chosen = Lottery::<String>::load_expect(match rng.gen_range(0, 5) {
assets::load_expect::<Lottery<String>>(match rng.gen_range(0, 5) { 0 => "common.loot_tables.loot_table_humanoids",
0 => "common.loot_tables.loot_table_humanoids", 1 => "common.loot_tables.loot_table_armor_misc",
1 => "common.loot_tables.loot_table_armor_misc", _ => "common.loot_tables.loot_table_cultists",
_ => "common.loot_tables.loot_table_cultists", });
});
let chosen = chosen.choose(); let chosen = chosen.choose();
let entity = EntityInfo::at( let entity = EntityInfo::at(
tile_wcenter.map(|e| e as f32) tile_wcenter.map(|e| e as f32)
@ -479,8 +478,8 @@ impl Floor {
.with_alignment(comp::Alignment::Enemy) .with_alignment(comp::Alignment::Enemy)
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_automatic_name() .with_automatic_name()
.with_loot_drop(assets::load_expect_cloned(chosen)) .with_loot_drop(ItemAsset::load_expect_cloned(chosen))
.with_main_tool(assets::load_expect_cloned(match rng.gen_range(0, 6) { .with_main_tool(ItemAsset::load_expect_cloned(match rng.gen_range(0, 6) {
0 => "common.items.npc_weapons.axe.malachite_axe-0", 0 => "common.items.npc_weapons.axe.malachite_axe-0",
1 => "common.items.npc_weapons.sword.cultist_purp_2h-0", 1 => "common.items.npc_weapons.sword.cultist_purp_2h-0",
2 => "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 }; boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 };
if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d { if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d {
let chosen = assets::load_expect::<Lottery<String>>( let chosen = Lottery::<String>::load_expect(
"common.loot_tables.loot_table_boss_cultist-leader", "common.loot_tables.loot_table_boss_cultist-leader",
); );
let chosen = chosen.choose(); let chosen = chosen.choose();
@ -520,7 +519,7 @@ impl Floor {
"Cult Leader {}", "Cult Leader {}",
npc::get_npc_name(npc::NpcKind::Humanoid) 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) { match rng.gen_range(0, 1) {
//Add more possible cult leader npc_weapons here //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); supplement.add_entity(entity);
} }

View File

@ -17,10 +17,10 @@ use common::{
vol::{BaseVol, ReadVol, RectSizedVol, WriteVol}, vol::{BaseVol, ReadVol, RectSizedVol, WriteVol},
}; };
use rand::Rng; use rand::Rng;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub castle: castle::Colors, pub castle: castle::Colors,
pub dungeon: dungeon::Colors, pub dungeon: dungeon::Colors,

View File

@ -12,10 +12,10 @@ use common::{
vol::Vox, vol::Vox,
}; };
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub foundation: (u8, u8, u8), pub foundation: (u8, u8, u8),
pub floor: (u8, u8, u8), pub floor: (u8, u8, u8),

View File

@ -10,10 +10,10 @@ use common::{
vol::Vox, vol::Vox,
}; };
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub brick_base: (u8, u8, u8), pub brick_base: (u8, u8, u8),
pub floor_base: (u8, u8, u8), pub floor_base: (u8, u8, u8),

View File

@ -4,10 +4,10 @@ pub mod keep;
use super::skeleton::*; use super::skeleton::*;
use crate::{site::BlockMask, IndexRef}; use crate::{site::BlockMask, IndexRef};
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub house: house::Colors, pub house: house::Colors,
pub keep: keep::Colors, pub keep: keep::Colors,

View File

@ -10,10 +10,10 @@ pub use self::{
use crate::IndexRef; use crate::IndexRef;
use common::terrain::Block; use common::terrain::Block;
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub archetype: archetype::Colors, pub archetype: archetype::Colors,
} }

View File

@ -13,9 +13,9 @@ use crate::{
IndexRef, IndexRef,
}; };
use common::{ use common::{
assets, assets::Asset,
astar::Astar, astar::Astar,
comp::{self, bird_medium, humanoid, object, quadruped_small}, comp::{self, bird_medium, humanoid, item::ItemAsset, object, quadruped_small},
generation::{ChunkSupplement, EntityInfo}, generation::{ChunkSupplement, EntityInfo},
path::Path, path::Path,
spiral::Spiral2d, spiral::Spiral2d,
@ -26,11 +26,11 @@ use common::{
use fxhash::FxHasher64; use fxhash::FxHasher64;
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::{collections::VecDeque, f32, hash::BuildHasherDefault}; use std::{collections::VecDeque, f32, hash::BuildHasherDefault};
use vek::*; use vek::*;
#[derive(Deserialize, Serialize)] #[derive(Deserialize)]
pub struct Colors { pub struct Colors {
pub building: building::Colors, pub building: building::Colors,
@ -904,7 +904,7 @@ impl Settlement {
comp::Alignment::Tame comp::Alignment::Tame
}) })
.do_if(is_human && rng.gen(), |entity| { .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) { match rng.gen_range(0, 7) {
0 => "common.items.npc_weapons.tool.broom", 0 => "common.items.npc_weapons.tool.broom",
1 => "common.items.npc_weapons.tool.hoe", 1 => "common.items.npc_weapons.tool.hoe",