Address zesterer's comments

This commit is contained in:
Christof Petig 2023-10-17 22:10:19 +02:00
parent 22f8433d22
commit e22046c5f4
7 changed files with 95 additions and 78 deletions

View File

@ -27,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New arena building in desert cities, suitable for PVP, also NPCs like to watch the fights too - New arena building in desert cities, suitable for PVP, also NPCs like to watch the fights too
- The loading screen now displays status updates for singleplayer server and client initialization progress - The loading screen now displays status updates for singleplayer server and client initialization progress
- New Frost Gigas attacks & AI - New Frost Gigas attacks & AI
- Weapons and armor load from plugins - Allow plugins to add weapon and armor items
### Changed ### Changed

View File

@ -25,5 +25,4 @@ walkdir = "2.3.2"
[features] [features]
hot-reloading = ["assets_manager/hot-reloading"] hot-reloading = ["assets_manager/hot-reloading"]
asset_tweak = ["dep:serde", "hot-reloading"] asset_tweak = ["dep:serde", "hot-reloading"]
hashbrown = ["dep:hashbrown"] plugins = ["dep:serde", "dep:tar", "dep:hashbrown"]
plugins = ["dep:serde", "dep:tar"]

View File

@ -245,7 +245,7 @@ impl<V> Concatenate for Vec<V> {
} }
} }
#[cfg(feature = "hashbrown")] #[cfg(feature = "plugins")]
impl<K: Eq + Hash, V, S: BuildHasher> Concatenate for hashbrown::HashMap<K, V, S> { impl<K: Eq + Hash, V, S: BuildHasher> Concatenate for hashbrown::HashMap<K, V, S> {
fn concatenate(mut self, b: Self) -> Self { fn concatenate(mut self, b: Self) -> Self {
self.extend(b); self.extend(b);

View File

@ -14,8 +14,18 @@ struct PluginEntry {
cache: AssetCache<Tar>, cache: AssetCache<Tar>,
} }
/// The source combining filesystem and plugins (typically used via /// The location of this asset
/// CombinedCache) enum AssetSource {
FileSystem,
Plugin { index: usize },
}
struct SourceAndContents<'a>(AssetSource, FileContent<'a>);
/// This source combines assets loaded from the filesystem and from plugins.
/// It is typically used via the CombinedCache type.
///
/// A load will search through all sources and warn about unhandled duplicates.
pub struct CombinedSource { pub struct CombinedSource {
fs: AssetCache<FileSystem>, fs: AssetCache<FileSystem>,
plugin_list: RwLock<Vec<PluginEntry>>, plugin_list: RwLock<Vec<PluginEntry>>,
@ -31,34 +41,40 @@ impl CombinedSource {
} }
impl CombinedSource { impl CombinedSource {
fn read_multiple(&self, id: &str, ext: &str) -> Vec<(Option<usize>, FileContent<'_>)> { /// Look for an asset in all known sources
fn read_multiple(&self, id: &str, ext: &str) -> Vec<SourceAndContents<'_>> {
let mut result = Vec::new(); let mut result = Vec::new();
if let Ok(file_entry) = self.fs.raw_source().read(id, ext) { if let Ok(file_entry) = self.fs.raw_source().read(id, ext) {
result.push((None, file_entry)); result.push(SourceAndContents(AssetSource::FileSystem, file_entry));
} }
for (n, p) in self.plugin_list.read().unwrap().iter().enumerate() { for (n, p) in self.plugin_list.read().unwrap().iter().enumerate() {
if let Ok(entry) = p.cache.raw_source().read(id, ext) { if let Ok(entry) = p.cache.raw_source().read(id, ext) {
// the data is behind an RwLockReadGuard, so own it for returning // the data is behind an RwLockReadGuard, so own it for returning
result.push((Some(n), match entry { result.push(SourceAndContents(
AssetSource::Plugin { index: n },
match entry {
FileContent::Slice(s) => FileContent::Buffer(Vec::from(s)), FileContent::Slice(s) => FileContent::Buffer(Vec::from(s)),
FileContent::Buffer(b) => FileContent::Buffer(b), FileContent::Buffer(b) => FileContent::Buffer(b),
FileContent::Owned(s) => FileContent::Buffer(Vec::from(s.as_ref().as_ref())), FileContent::Owned(s) => {
})); FileContent::Buffer(Vec::from(s.as_ref().as_ref()))
},
},
));
} }
} }
result result
} }
// We don't want to keep the lock, so we clone /// Return the path of a source
fn plugin_path(&self, index: Option<usize>) -> Option<PathBuf> { fn plugin_path(&self, index: &AssetSource) -> Option<PathBuf> {
if let Some(index) = index { match index {
self.plugin_list AssetSource::FileSystem => Some(ASSETS_PATH.clone()),
AssetSource::Plugin { index } => self.plugin_list
.read() .read()
.unwrap() .unwrap()
.get(index) .get(*index)
.map(|plugin| plugin.path.clone()) // We don't want to keep the lock, so we clone
} else { .map(|plugin| plugin.path.clone()),
None
} }
} }
} }
@ -71,12 +87,11 @@ impl Source for CombinedSource {
Err(std::io::ErrorKind::NotFound.into()) Err(std::io::ErrorKind::NotFound.into())
} else { } else {
if entries.len() > 1 { if entries.len() > 1 {
let plugina = self.plugin_path(entries[0].0); let patha = self.plugin_path(&entries[0].0);
let pluginb = self.plugin_path(entries[1].0); let pathb = self.plugin_path(&entries[1].0);
let patha = plugina.as_ref().unwrap_or(&ASSETS_PATH);
let pathb = pluginb.as_ref().unwrap_or(&ASSETS_PATH);
tracing::error!("Duplicate asset {id} in {patha:?} and {pathb:?}"); tracing::error!("Duplicate asset {id} in {patha:?} and {pathb:?}");
} }
// unconditionally return the first asset found
Ok(entries.swap_remove(0).1) Ok(entries.swap_remove(0).1)
} }
} }
@ -119,7 +134,7 @@ impl CombinedCache {
/// Combine objects from filesystem and plugins /// Combine objects from filesystem and plugins
pub fn combine<T: Concatenate>( pub fn combine<T: Concatenate>(
&self, &self,
load_from: impl Fn(AnyCache) -> Result<T, BoxedError>, mut load_from: impl FnMut(AnyCache) -> Result<T, BoxedError>,
) -> Result<T, BoxedError> { ) -> Result<T, BoxedError> {
let mut result = load_from(self.0.raw_source().fs.as_any_cache()); let mut result = load_from(self.0.raw_source().fs.as_any_cache());
// Report a severe error from the filesystem asset even if later overwritten by // Report a severe error from the filesystem asset even if later overwritten by
@ -162,6 +177,8 @@ impl CombinedCache {
result result
} }
/// Add a tar archive (a plugin) to the system.
/// All files in that tar file become potential assets.
pub fn register_tar(&self, path: PathBuf) -> std::io::Result<()> { pub fn register_tar(&self, path: PathBuf) -> std::io::Result<()> {
let tar_source = Tar::from_path(&path)?; let tar_source = Tar::from_path(&path)?;
let cache = AssetCache::with_source(tar_source); let cache = AssetCache::with_source(tar_source);
@ -175,6 +192,7 @@ impl CombinedCache {
} }
} }
// Delegate all cache operations directly to the contained cache object
impl std::ops::Deref for CombinedCache { impl std::ops::Deref for CombinedCache {
type Target = AssetCache<CombinedSource>; type Target = AssetCache<CombinedSource>;

View File

@ -119,7 +119,7 @@ impl Backend {
fn read(&self, pos: u64, len: usize) -> std::io::Result<Vec<u8>> { fn read(&self, pos: u64, len: usize) -> std::io::Result<Vec<u8>> {
File::open(self.0.clone()).and_then(|file| { File::open(self.0.clone()).and_then(|file| {
let mut result = vec![0; len]; let mut result = vec![0; len];
file.read_at(result.as_mut_slice(), pos) file.read_exact_at(result.as_mut_slice(), pos)
.map(move |_num_bytes| result) .map(move |_num_bytes| result)
}) })
} }

View File

@ -27,7 +27,7 @@ singleplayer = ["server"]
simd = ["vek/platform_intrinsics"] simd = ["vek/platform_intrinsics"]
tracy = ["common-frontend/tracy", "client/tracy"] tracy = ["common-frontend/tracy", "client/tracy"]
tracy-memory = ["tracy"] # enables heap profiling with tracy tracy-memory = ["tracy"] # enables heap profiling with tracy
plugins = ["client/plugins", "common-assets/plugins", "common-assets/hashbrown"] plugins = ["client/plugins", "common-assets/plugins"]
egui-ui = ["voxygen-egui", "egui", "egui_wgpu_backend", "egui_winit_platform"] egui-ui = ["voxygen-egui", "egui", "egui_wgpu_backend", "egui_winit_platform"]
shaderc-from-source = ["shaderc/build-from-source"] shaderc-from-source = ["shaderc/build-from-source"]
discord = ["discord-sdk"] discord = ["discord-sdk"]

View File

@ -178,7 +178,7 @@ macro_rules! make_vox_spec {
} }
} }
} }
macro_rules! concatenate_tuple { macro_rules! impl_concatenate_for_wrapper {
($name:ty) => { ($name:ty) => {
impl Concatenate for $name { impl Concatenate for $name {
fn concatenate(self, b: Self) -> Self { Self(self.0.concatenate(b.0)) } fn concatenate(self, b: Self) -> Self { Self(self.0.concatenate(b.0)) }
@ -375,7 +375,7 @@ impl HumHeadSpec {
) )
} }
} }
concatenate_tuple!(HumHeadSpec); impl_concatenate_for_wrapper!(HumHeadSpec);
// Armor aspects should be in the same order, top to bottom. // Armor aspects should be in the same order, top to bottom.
// These seem overly split up, but wanted to keep the armor seperated // These seem overly split up, but wanted to keep the armor seperated
@ -398,43 +398,43 @@ impl<K: Hash + Eq, S> Concatenate for ArmorVoxSpecMap<K, S> {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorShoulderSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>); struct HumArmorShoulderSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
concatenate_tuple!(HumArmorShoulderSpec); impl_concatenate_for_wrapper!(HumArmorShoulderSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorChestSpec); impl_concatenate_for_wrapper!(HumArmorChestSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>); struct HumArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
concatenate_tuple!(HumArmorHandSpec); impl_concatenate_for_wrapper!(HumArmorHandSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorBeltSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorBeltSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorBeltSpec); impl_concatenate_for_wrapper!(HumArmorBeltSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorBackSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorBackSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorBackSpec); impl_concatenate_for_wrapper!(HumArmorBackSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorPantsSpec); impl_concatenate_for_wrapper!(HumArmorPantsSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorFootSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorFootSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorFootSpec); impl_concatenate_for_wrapper!(HumArmorFootSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumMainWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>); struct HumMainWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>);
concatenate_tuple!(HumMainWeaponSpec); impl_concatenate_for_wrapper!(HumMainWeaponSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumModularComponentSpec(HashMap<String, ModularComponentSpec>); struct HumModularComponentSpec(HashMap<String, ModularComponentSpec>);
concatenate_tuple!(HumModularComponentSpec); impl_concatenate_for_wrapper!(HumModularComponentSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorLanternSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorLanternSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorLanternSpec); impl_concatenate_for_wrapper!(HumArmorLanternSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorGliderSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorGliderSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorGliderSpec); impl_concatenate_for_wrapper!(HumArmorGliderSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorHeadSpec(ArmorVoxSpecMap<(Species, BodyType, String), ArmorVoxSpec>); struct HumArmorHeadSpec(ArmorVoxSpecMap<(Species, BodyType, String), ArmorVoxSpec>);
concatenate_tuple!(HumArmorHeadSpec); impl_concatenate_for_wrapper!(HumArmorHeadSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct HumArmorTabardSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct HumArmorTabardSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(HumArmorTabardSpec); impl_concatenate_for_wrapper!(HumArmorTabardSpec);
make_vox_spec!( make_vox_spec!(
Body, Body,
@ -1105,7 +1105,7 @@ fn mesh_hold() -> BoneMeshes {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedSmallCentralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSCentralVoxSpec>); struct QuadrupedSmallCentralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSCentralVoxSpec>);
concatenate_tuple!(QuadrupedSmallCentralSpec); impl_concatenate_for_wrapper!(QuadrupedSmallCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQSCentralVoxSpec { struct SidedQSCentralVoxSpec {
@ -1123,7 +1123,7 @@ struct QuadrupedSmallCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedSmallLateralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSLateralVoxSpec>); struct QuadrupedSmallLateralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSLateralVoxSpec>);
concatenate_tuple!(QuadrupedSmallLateralSpec); impl_concatenate_for_wrapper!(QuadrupedSmallLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQSLateralVoxSpec { struct SidedQSLateralVoxSpec {
@ -1322,7 +1322,7 @@ impl QuadrupedSmallLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedMediumCentralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMCentralVoxSpec>); struct QuadrupedMediumCentralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMCentralVoxSpec>);
concatenate_tuple!(QuadrupedMediumCentralSpec); impl_concatenate_for_wrapper!(QuadrupedMediumCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQMCentralVoxSpec { struct SidedQMCentralVoxSpec {
@ -1344,7 +1344,7 @@ struct QuadrupedMediumCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedMediumLateralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMLateralVoxSpec>); struct QuadrupedMediumLateralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMLateralVoxSpec>);
concatenate_tuple!(QuadrupedMediumLateralSpec); impl_concatenate_for_wrapper!(QuadrupedMediumLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQMLateralVoxSpec { struct SidedQMLateralVoxSpec {
leg_fl: QuadrupedMediumLateralSubSpec, leg_fl: QuadrupedMediumLateralSubSpec,
@ -1700,7 +1700,7 @@ impl QuadrupedMediumLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct BirdMediumCentralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMCentralVoxSpec>); struct BirdMediumCentralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMCentralVoxSpec>);
concatenate_tuple!(BirdMediumCentralSpec); impl_concatenate_for_wrapper!(BirdMediumCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBMCentralVoxSpec { struct SidedBMCentralVoxSpec {
@ -1718,7 +1718,7 @@ struct BirdMediumCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct BirdMediumLateralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMLateralVoxSpec>); struct BirdMediumLateralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMLateralVoxSpec>);
concatenate_tuple!(BirdMediumLateralSpec); impl_concatenate_for_wrapper!(BirdMediumLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBMLateralVoxSpec { struct SidedBMLateralVoxSpec {
@ -1956,7 +1956,7 @@ impl BirdMediumLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct TheropodCentralSpec(HashMap<(TSpecies, TBodyType), SidedTCentralVoxSpec>); struct TheropodCentralSpec(HashMap<(TSpecies, TBodyType), SidedTCentralVoxSpec>);
concatenate_tuple!(TheropodCentralSpec); impl_concatenate_for_wrapper!(TheropodCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedTCentralVoxSpec { struct SidedTCentralVoxSpec {
@ -1977,7 +1977,7 @@ struct TheropodCentralSubSpec {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct TheropodLateralSpec(HashMap<(TSpecies, TBodyType), SidedTLateralVoxSpec>); struct TheropodLateralSpec(HashMap<(TSpecies, TBodyType), SidedTLateralVoxSpec>);
concatenate_tuple!(TheropodLateralSpec); impl_concatenate_for_wrapper!(TheropodLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedTLateralVoxSpec { struct SidedTLateralVoxSpec {
@ -2288,7 +2288,7 @@ impl TheropodLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct ArthropodCentralSpec(HashMap<(ASpecies, ABodyType), SidedACentralVoxSpec>); struct ArthropodCentralSpec(HashMap<(ASpecies, ABodyType), SidedACentralVoxSpec>);
concatenate_tuple!(ArthropodCentralSpec); impl_concatenate_for_wrapper!(ArthropodCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedACentralVoxSpec { struct SidedACentralVoxSpec {
@ -2304,7 +2304,7 @@ struct ArthropodCentralSubSpec {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct ArthropodLateralSpec(HashMap<(ASpecies, ABodyType), SidedALateralVoxSpec>); struct ArthropodLateralSpec(HashMap<(ASpecies, ABodyType), SidedALateralVoxSpec>);
concatenate_tuple!(ArthropodLateralSpec); impl_concatenate_for_wrapper!(ArthropodLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedALateralVoxSpec { struct SidedALateralVoxSpec {
@ -2690,7 +2690,7 @@ impl ArthropodLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>); struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>);
concatenate_tuple!(FishMediumCentralSpec); impl_concatenate_for_wrapper!(FishMediumCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedFMCentralVoxSpec { struct SidedFMCentralVoxSpec {
@ -2709,7 +2709,7 @@ struct FishMediumCentralSubSpec {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct FishMediumLateralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMLateralVoxSpec>); struct FishMediumLateralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMLateralVoxSpec>);
concatenate_tuple!(FishMediumLateralSpec); impl_concatenate_for_wrapper!(FishMediumLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedFMLateralVoxSpec { struct SidedFMLateralVoxSpec {
fin_l: FishMediumLateralSubSpec, fin_l: FishMediumLateralSubSpec,
@ -2898,7 +2898,7 @@ impl FishMediumLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct FishSmallCentralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSCentralVoxSpec>); struct FishSmallCentralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSCentralVoxSpec>);
concatenate_tuple!(FishSmallCentralSpec); impl_concatenate_for_wrapper!(FishSmallCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedFSCentralVoxSpec { struct SidedFSCentralVoxSpec {
@ -2914,7 +2914,7 @@ struct FishSmallCentralSubSpec {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct FishSmallLateralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSLateralVoxSpec>); struct FishSmallLateralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSLateralVoxSpec>);
concatenate_tuple!(FishSmallLateralSpec); impl_concatenate_for_wrapper!(FishSmallLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedFSLateralVoxSpec { struct SidedFSLateralVoxSpec {
fin_l: FishSmallLateralSubSpec, fin_l: FishSmallLateralSubSpec,
@ -3045,25 +3045,25 @@ impl FishSmallLateralSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>); struct BipedSmallWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>);
concatenate_tuple!(BipedSmallWeaponSpec); impl_concatenate_for_wrapper!(BipedSmallWeaponSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorHeadSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct BipedSmallArmorHeadSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorHeadSpec); impl_concatenate_for_wrapper!(BipedSmallArmorHeadSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>); struct BipedSmallArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorHandSpec); impl_concatenate_for_wrapper!(BipedSmallArmorHandSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorFootSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>); struct BipedSmallArmorFootSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorFootSpec); impl_concatenate_for_wrapper!(BipedSmallArmorFootSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct BipedSmallArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorChestSpec); impl_concatenate_for_wrapper!(BipedSmallArmorChestSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct BipedSmallArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorPantsSpec); impl_concatenate_for_wrapper!(BipedSmallArmorPantsSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedSmallArmorTailSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>); struct BipedSmallArmorTailSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
concatenate_tuple!(BipedSmallArmorTailSpec); impl_concatenate_for_wrapper!(BipedSmallArmorTailSpec);
make_vox_spec!( make_vox_spec!(
biped_small::Body, biped_small::Body,
struct BipedSmallSpec { struct BipedSmallSpec {
@ -3327,7 +3327,7 @@ impl BipedSmallWeaponSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct DragonCentralSpec(HashMap<(DSpecies, DBodyType), SidedDCentralVoxSpec>); struct DragonCentralSpec(HashMap<(DSpecies, DBodyType), SidedDCentralVoxSpec>);
concatenate_tuple!(DragonCentralSpec); impl_concatenate_for_wrapper!(DragonCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedDCentralVoxSpec { struct SidedDCentralVoxSpec {
@ -3349,7 +3349,7 @@ struct DragonCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>); struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>);
concatenate_tuple!(DragonLateralSpec); impl_concatenate_for_wrapper!(DragonLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedDLateralVoxSpec { struct SidedDLateralVoxSpec {
@ -3700,7 +3700,7 @@ impl DragonLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct BirdLargeCentralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLACentralVoxSpec>); struct BirdLargeCentralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLACentralVoxSpec>);
concatenate_tuple!(BirdLargeCentralSpec); impl_concatenate_for_wrapper!(BirdLargeCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBLACentralVoxSpec { struct SidedBLACentralVoxSpec {
@ -3721,7 +3721,7 @@ struct BirdLargeCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct BirdLargeLateralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLALateralVoxSpec>); struct BirdLargeLateralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLALateralVoxSpec>);
concatenate_tuple!(BirdLargeLateralSpec); impl_concatenate_for_wrapper!(BirdLargeLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBLALateralVoxSpec { struct SidedBLALateralVoxSpec {
@ -4105,7 +4105,7 @@ impl BirdLargeLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedLargeCentralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLCentralVoxSpec>); struct BipedLargeCentralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLCentralVoxSpec>);
concatenate_tuple!(BipedLargeCentralSpec); impl_concatenate_for_wrapper!(BipedLargeCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBLCentralVoxSpec { struct SidedBLCentralVoxSpec {
@ -4125,7 +4125,7 @@ struct BipedLargeCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedLargeLateralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLLateralVoxSpec>); struct BipedLargeLateralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLLateralVoxSpec>);
concatenate_tuple!(BipedLargeLateralSpec); impl_concatenate_for_wrapper!(BipedLargeLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedBLLateralVoxSpec { struct SidedBLLateralVoxSpec {
@ -4147,10 +4147,10 @@ struct BipedLargeLateralSubSpec {
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedLargeMainSpec(HashMap<ToolKey, ArmorVoxSpec>); struct BipedLargeMainSpec(HashMap<ToolKey, ArmorVoxSpec>);
concatenate_tuple!(BipedLargeMainSpec); impl_concatenate_for_wrapper!(BipedLargeMainSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct BipedLargeSecondSpec(HashMap<ToolKey, ArmorVoxSpec>); struct BipedLargeSecondSpec(HashMap<ToolKey, ArmorVoxSpec>);
concatenate_tuple!(BipedLargeSecondSpec); impl_concatenate_for_wrapper!(BipedLargeSecondSpec);
make_vox_spec!( make_vox_spec!(
biped_large::Body, biped_large::Body,
struct BipedLargeSpec { struct BipedLargeSpec {
@ -4528,7 +4528,7 @@ impl BipedLargeSecondSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>); struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>);
concatenate_tuple!(GolemCentralSpec); impl_concatenate_for_wrapper!(GolemCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedGCentralVoxSpec { struct SidedGCentralVoxSpec {
@ -4547,7 +4547,7 @@ struct GolemCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct GolemLateralSpec(HashMap<(GSpecies, GBodyType), SidedGLateralVoxSpec>); struct GolemLateralSpec(HashMap<(GSpecies, GBodyType), SidedGLateralVoxSpec>);
concatenate_tuple!(GolemLateralSpec); impl_concatenate_for_wrapper!(GolemLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedGLateralVoxSpec { struct SidedGLateralVoxSpec {
@ -4840,7 +4840,7 @@ impl GolemLateralSpec {
////// //////
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedLowCentralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLCentralVoxSpec>); struct QuadrupedLowCentralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLCentralVoxSpec>);
concatenate_tuple!(QuadrupedLowCentralSpec); impl_concatenate_for_wrapper!(QuadrupedLowCentralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQLCentralVoxSpec { struct SidedQLCentralVoxSpec {
@ -4861,7 +4861,7 @@ struct QuadrupedLowCentralSubSpec {
#[derive(Deserialize)] #[derive(Deserialize)]
struct QuadrupedLowLateralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLLateralVoxSpec>); struct QuadrupedLowLateralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLLateralVoxSpec>);
concatenate_tuple!(QuadrupedLowLateralSpec); impl_concatenate_for_wrapper!(QuadrupedLowLateralSpec);
#[derive(Deserialize)] #[derive(Deserialize)]
struct SidedQLLateralVoxSpec { struct SidedQLLateralVoxSpec {
front_left: QuadrupedLowLateralSubSpec, front_left: QuadrupedLowLateralSubSpec,
@ -5191,7 +5191,7 @@ impl ObjectCentralSpec {
(central, Vec3::from(spec.bone1.offset)) (central, Vec3::from(spec.bone1.offset))
} }
} }
concatenate_tuple!(ObjectCentralSpec); impl_concatenate_for_wrapper!(ObjectCentralSpec);
struct ModelWithOptionalIndex(String, u32); struct ModelWithOptionalIndex(String, u32);
@ -5229,7 +5229,7 @@ impl<'de> Deserialize<'de> for ModelWithOptionalIndex {
#[derive(Deserialize)] #[derive(Deserialize)]
struct ItemDropCentralSpec(HashMap<ItemKey, ModelWithOptionalIndex>); struct ItemDropCentralSpec(HashMap<ItemKey, ModelWithOptionalIndex>);
concatenate_tuple!(ItemDropCentralSpec); impl_concatenate_for_wrapper!(ItemDropCentralSpec);
make_vox_spec!( make_vox_spec!(
item_drop::Body, item_drop::Body,