veloren_voxygen/scene/figure/
load.rs

1use super::cache::{
2    FigureKey, FigureModelEntryFuture, ModelEntryFuture, TerrainModelEntryFuture, ToolKey,
3};
4use common::{
5    assets::{self, AssetExt, AssetHandle, Concatenate, DotVoxAsset, MultiRon, ReloadWatcher},
6    comp::{
7        arthropod::{self, BodyType as ABodyType, Species as ASpecies},
8        biped_large::{self, BodyType as BLBodyType, Species as BLSpecies},
9        biped_small,
10        bird_large::{self, BodyType as BLABodyType, Species as BLASpecies},
11        bird_medium::{self, BodyType as BMBodyType, Species as BMSpecies},
12        body,
13        crustacean::{self, BodyType as CBodyType, Species as CSpecies},
14        dragon::{self, BodyType as DBodyType, Species as DSpecies},
15        fish_medium::{self, BodyType as FMBodyType, Species as FMSpecies},
16        fish_small::{self, BodyType as FSBodyType, Species as FSSpecies},
17        golem::{self, BodyType as GBodyType, Species as GSpecies},
18        humanoid::{self, Body, BodyType, EyeColor, Skin, Species},
19        item::item_key::ItemKey,
20        object,
21        quadruped_low::{self, BodyType as QLBodyType, Species as QLSpecies},
22        quadruped_medium::{self, BodyType as QMBodyType, Species as QMSpecies},
23        quadruped_small::{self, BodyType as QSBodyType, Species as QSSpecies},
24        ship::{
25            self,
26            figuredata::{ShipSpec, VoxelCollider},
27        },
28        theropod::{self, BodyType as TBodyType, Species as TSpecies},
29    },
30    figure::{Cell, DynaUnionizer, MatCell, MatSegment, Material, Segment},
31    terrain::Block,
32    vol::{IntoFullPosIterator, ReadVol},
33    volumes::dyna::Dyna,
34};
35use hashbrown::HashMap;
36use serde::{Deserialize, Deserializer};
37use std::{fmt, hash::Hash};
38use tracing::{error, warn};
39use vek::*;
40
41pub type BoneMeshes = (Segment, Vec3<f32>);
42
43const DEFAULT_INDEX: u32 = 0;
44
45fn load_segment(mesh_name: &str) -> Segment {
46    let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
47    Segment::from_vox_model_index(
48        &DotVoxAsset::load_expect(&full_specifier).read().0,
49        DEFAULT_INDEX as usize,
50    )
51}
52fn graceful_load_vox(mesh_name: &str) -> AssetHandle<DotVoxAsset> {
53    let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
54    graceful_load_vox_fullspec(&full_specifier)
55}
56fn graceful_load_vox_fullspec(full_specifier: &str) -> AssetHandle<DotVoxAsset> {
57    match DotVoxAsset::load(full_specifier) {
58        Ok(dot_vox) => dot_vox,
59        Err(_) => {
60            error!(?full_specifier, "Could not load vox file for figure");
61            DotVoxAsset::load_expect("voxygen.voxel.not_found")
62        },
63    }
64}
65fn graceful_load_segment(mesh_name: &str, model_index: u32) -> Segment {
66    Segment::from_vox_model_index(&graceful_load_vox(mesh_name).read().0, model_index as usize)
67}
68fn graceful_load_segment_fullspec(full_specifier: &str, model_index: u32) -> Segment {
69    Segment::from_vox_model_index(
70        &graceful_load_vox_fullspec(full_specifier).read().0,
71        model_index as usize,
72    )
73}
74fn graceful_load_segment_flipped(mesh_name: &str, flipped: bool, model_index: u32) -> Segment {
75    Segment::from_vox(
76        &graceful_load_vox(mesh_name).read().0,
77        flipped,
78        model_index as usize,
79    )
80}
81fn graceful_load_mat_segment(mesh_name: &str, model_index: u32) -> MatSegment {
82    MatSegment::from_vox_model_index(&graceful_load_vox(mesh_name).read().0, model_index as usize)
83}
84fn graceful_load_mat_segment_flipped(mesh_name: &str, model_index: u32) -> MatSegment {
85    MatSegment::from_vox(
86        &graceful_load_vox(mesh_name).read().0,
87        true,
88        model_index as usize,
89    )
90}
91
92pub fn load_mesh(mesh_name: &str, position: Vec3<f32>) -> BoneMeshes {
93    (load_segment(mesh_name), position)
94}
95
96fn recolor_grey(rgb: Rgb<u8>, color: Rgb<u8>) -> Rgb<u8> {
97    use common::util::{linear_to_srgb, srgb_to_linear_fast};
98
99    const BASE_GREY: f32 = 178.0;
100    if rgb.r == rgb.g && rgb.g == rgb.b {
101        let c1 = srgb_to_linear_fast(rgb.map(|e| e as f32 / BASE_GREY));
102        let c2 = srgb_to_linear_fast(color.map(|e| e as f32 / 255.0));
103
104        linear_to_srgb(c1 * c2).map(|e| (e.clamp(0.0, 1.0) * 255.0) as u8)
105    } else {
106        rgb
107    }
108}
109
110/// A set of reloadable specifications for a Body.
111pub trait BodySpec: Sized {
112    type Spec;
113    /// Cloned on each cache invalidation. If this type is expensive to clone,
114    /// place it behind an [`Arc`].
115    type Manifests: Send + Sync + Clone;
116    type Extra: Send + Sync;
117    type BoneMesh;
118    type ModelEntryFuture<const N: usize>: ModelEntryFuture<N>;
119
120    /// Initialize all the specifications for this Body.
121    fn load_spec() -> Result<Self::Manifests, assets::Error>;
122
123    /// Determine whether the cache's manifest was reloaded
124    fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher;
125
126    /// Mesh bones using the given spec, character state, and mesh generation
127    /// function.
128    ///
129    /// NOTE: We deliberately call this function with only the key into the
130    /// cache, to enforce that the cached state only depends on the key.  We
131    /// may end up using a mechanism different from this cache eventually,
132    /// in which case this strategy might change.
133    fn bone_meshes(
134        key: &FigureKey<Self>,
135        manifests: &Self::Manifests,
136        extra: Self::Extra,
137    ) -> [Option<Self::BoneMesh>; anim::MAX_BONE_COUNT];
138}
139
140macro_rules! make_vox_spec {
141    (
142        $body:ty,
143        struct $Spec:ident { $( $(+)? $field:ident: $ty:ty = $asset_path:literal),* $(,)? },
144        |$self_pat:pat, $spec_pat:pat_param| $bone_meshes:block $(,)?
145    ) => {
146        #[derive(Clone)]
147        pub struct $Spec {
148            $( $field: AssetHandle<MultiRon<$ty>>, )*
149        }
150
151        impl assets::Compound for $Spec {
152            fn load(_: assets::AnyCache, _: &assets::SharedString) -> Result<Self, assets::BoxedError> {
153                Ok($Spec {
154                    $( $field: AssetExt::load($asset_path)?, )*
155                })
156            }
157        }
158
159        impl BodySpec for $body {
160            type Spec = $Spec;
161            type Manifests = AssetHandle<Self::Spec>;
162            type Extra = ();
163            type BoneMesh = BoneMeshes;
164            type ModelEntryFuture<const N: usize> = FigureModelEntryFuture<N>;
165
166            fn load_spec() -> Result<Self::Manifests, assets::Error> {
167                Self::Spec::load("")
168            }
169
170            fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() }
171
172            fn bone_meshes(
173                $self_pat: &FigureKey<Self>,
174                manifests: &Self::Manifests,
175                _: Self::Extra,
176            ) -> [Option<BoneMeshes>; anim::MAX_BONE_COUNT] {
177                let $spec_pat = &*manifests.read();
178                $bone_meshes
179            }
180        }
181    }
182}
183macro_rules! impl_concatenate_for_wrapper {
184    ($name:ty) => {
185        impl Concatenate for $name {
186            fn concatenate(self, b: Self) -> Self { Self(self.0.concatenate(b.0)) }
187        }
188    };
189}
190
191// All offsets should be relative to an initial origin that doesn't change when
192// combining segments
193#[derive(Deserialize)]
194struct VoxSpec<T>(String, [T; 3], #[serde(default)] u32);
195
196#[derive(Deserialize)]
197struct VoxSimple(String);
198
199impl Default for VoxSimple {
200    fn default() -> Self { VoxSimple("armor.empty".to_string()) }
201}
202
203#[derive(Deserialize)]
204struct VoxMirror(String, bool);
205
206impl Default for VoxMirror {
207    fn default() -> Self { VoxMirror("armor.empty".to_string(), false) }
208}
209
210#[derive(Deserialize)]
211struct ArmorVoxSpec {
212    vox_spec: VoxSpec<f32>,
213    color: Option<[u8; 3]>,
214}
215
216#[derive(Deserialize)]
217#[expect(dead_code)]
218enum ModularComponentSpec {
219    /// item id, offset from origin to mount point
220    Damage((String, [i32; 3])),
221    /// item id, offset from origin to hand, offset from origin to mount point
222    Held((String, [f32; 3], [i32; 3])),
223}
224
225// For use by armor with a left and right component
226#[derive(Deserialize)]
227struct SidedArmorVoxSpec {
228    left: ArmorVoxSpec,
229    right: ArmorVoxSpec,
230    /// FIXME: Either use this, or remove it.
231    #[expect(dead_code)]
232    color: Option<[u8; 3]>,
233}
234
235/// Color information not found in voxels, for humanoids.
236#[derive(Deserialize)]
237struct HumColorSpec {
238    hair_colors: humanoid::species::PureCases<Vec<(u8, u8, u8)>>,
239    eye_colors_light: humanoid::eye_color::PureCases<(u8, u8, u8)>,
240    eye_colors_dark: humanoid::eye_color::PureCases<(u8, u8, u8)>,
241    eye_white: (u8, u8, u8),
242    skin_colors_plain: humanoid::skin::PureCases<(u8, u8, u8)>,
243    skin_colors_light: humanoid::skin::PureCases<(u8, u8, u8)>,
244    skin_colors_dark: humanoid::skin::PureCases<(u8, u8, u8)>,
245}
246
247impl HumColorSpec {
248    fn hair_color(&self, species: Species, val: u8) -> (u8, u8, u8) {
249        species
250            .elim_case_pure(&self.hair_colors)
251            .get(val as usize)
252            .copied()
253            .unwrap_or((0, 0, 0))
254    }
255
256    fn color_segment(
257        &self,
258        mat_segment: MatSegment,
259        skin: Skin,
260        hair_color: (u8, u8, u8),
261        eye_color: EyeColor,
262    ) -> Segment {
263        // TODO move some of the colors to common
264        mat_segment.to_segment(|mat| {
265            match mat {
266                Material::Skin => *skin.elim_case_pure(&self.skin_colors_plain),
267                Material::SkinDark => *skin.elim_case_pure(&self.skin_colors_dark),
268                Material::SkinLight => *skin.elim_case_pure(&self.skin_colors_light),
269                Material::Hair => hair_color,
270                // TODO add back multiple colors
271                Material::EyeLight => *eye_color.elim_case_pure(&self.eye_colors_light),
272                Material::EyeDark => *eye_color.elim_case_pure(&self.eye_colors_dark),
273                Material::EyeWhite => self.eye_white,
274            }
275            .into()
276        })
277    }
278}
279
280impl Concatenate for HumColorSpec {
281    fn concatenate(self, _b: Self) -> Self { todo!("Can't concatenate HumColorSpec") }
282}
283
284// All reliant on humanoid::Species and humanoid::BodyType
285#[derive(Deserialize)]
286struct HumHeadSubSpec {
287    offset: [f32; 3], // Should be relative to initial origin
288    head: VoxSpec<i32>,
289    eyes: Vec<Option<VoxSpec<i32>>>,
290    hair: Vec<Option<VoxSpec<i32>>>,
291    beard: Vec<Option<VoxSpec<i32>>>,
292    accessory: Vec<Option<VoxSpec<i32>>>,
293}
294#[derive(Deserialize)]
295struct HumHeadSpec(HashMap<(Species, BodyType), HumHeadSubSpec>);
296
297impl HumHeadSpec {
298    fn mesh_head(
299        &self,
300        body: &Body,
301        color_spec: &HumColorSpec,
302        helmet: Option<(Segment, Vec3<i32>)>,
303    ) -> BoneMeshes {
304        let spec = match self.0.get(&(body.species, body.body_type)) {
305            Some(spec) => spec,
306            None => {
307                error!(
308                    ?body.species,
309                    ?body.body_type,
310                    "No head specification exists for the combination of species and body"
311                );
312                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
313            },
314        };
315
316        let hair_color = color_spec.hair_color(body.species, body.hair_color);
317        let hair_rgb = hair_color.into();
318        let skin_rgb = body.species.skin_color(body.skin);
319        let eye_rgb = body.species.eye_color(body.eye_color);
320
321        // Load segment pieces
322        let bare_head = graceful_load_mat_segment(&spec.head.0, spec.head.2);
323
324        let eyes = match spec.eyes.get(body.eyes as usize) {
325            Some(Some(spec)) => Some((
326                color_spec.color_segment(
327                    graceful_load_mat_segment(&spec.0, spec.2)
328                        .map_rgb(|rgb| recolor_grey(rgb, hair_rgb)),
329                    skin_rgb,
330                    hair_color,
331                    eye_rgb,
332                ),
333                Vec3::from(spec.1),
334            )),
335            Some(None) => None,
336            None => {
337                warn!("No specification for these eyes: {:?}", body.eyes);
338                None
339            },
340        };
341        let hair = match spec.hair.get(body.hair_style as usize) {
342            Some(Some(spec)) => Some((
343                graceful_load_segment(&spec.0, spec.2).map_rgb(|rgb| recolor_grey(rgb, hair_rgb)),
344                Vec3::from(spec.1),
345            )),
346            Some(None) => None,
347            None => {
348                warn!("No specification for hair style {}", body.hair_style);
349                None
350            },
351        };
352        let beard = match spec.beard.get(body.beard as usize) {
353            Some(Some(spec)) => Some((
354                graceful_load_segment(&spec.0, spec.2).map_rgb(|rgb| recolor_grey(rgb, hair_rgb)),
355                Vec3::from(spec.1),
356            )),
357            Some(None) => None,
358            None => {
359                warn!("No specification for this beard: {:?}", body.beard);
360                None
361            },
362        };
363        let accessory = match spec.accessory.get(body.accessory as usize) {
364            Some(Some(spec)) => Some((graceful_load_segment(&spec.0, spec.2), Vec3::from(spec.1))),
365            Some(None) => None,
366            None => {
367                warn!("No specification for this accessory: {:?}", body.accessory);
368                None
369            },
370        };
371
372        let (head, origin_offset) = DynaUnionizer::new()
373            .add(
374                color_spec.color_segment(bare_head, skin_rgb, hair_color, eye_rgb),
375                spec.head.1.into(),
376            )
377            .maybe_add(eyes)
378            .maybe_add(hair)
379            .maybe_add(beard)
380            .maybe_add(accessory)
381            .maybe_add(helmet)
382            .unify_with(|v| if v.is_hollow() { Cell::Empty } else { v });
383        (
384            head,
385            Vec3::from(spec.offset) + origin_offset.map(|e| e as f32 * -1.0),
386        )
387    }
388}
389impl_concatenate_for_wrapper!(HumHeadSpec);
390
391// Armor aspects should be in the same order, top to bottom.
392// These seem overly split up, but wanted to keep the armor seperated
393// unlike head which is done above.
394#[derive(Deserialize)]
395struct ArmorVoxSpecMap<K, S>
396where
397    K: Hash + Eq,
398{
399    default: S,
400    map: HashMap<K, S>,
401}
402impl<K: Hash + Eq, S> Concatenate for ArmorVoxSpecMap<K, S> {
403    fn concatenate(self, b: Self) -> Self {
404        Self {
405            default: self.default,
406            map: self.map.concatenate(b.map),
407        }
408    }
409}
410#[derive(Deserialize)]
411struct HumArmorShoulderSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
412impl_concatenate_for_wrapper!(HumArmorShoulderSpec);
413#[derive(Deserialize)]
414struct HumArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
415impl_concatenate_for_wrapper!(HumArmorChestSpec);
416#[derive(Deserialize)]
417struct HumArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
418impl_concatenate_for_wrapper!(HumArmorHandSpec);
419#[derive(Deserialize)]
420struct HumArmorBeltSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
421impl_concatenate_for_wrapper!(HumArmorBeltSpec);
422#[derive(Deserialize)]
423struct HumArmorBackSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
424impl_concatenate_for_wrapper!(HumArmorBackSpec);
425#[derive(Deserialize)]
426struct HumArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
427impl_concatenate_for_wrapper!(HumArmorPantsSpec);
428#[derive(Deserialize)]
429struct HumArmorFootSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
430impl_concatenate_for_wrapper!(HumArmorFootSpec);
431#[derive(Deserialize)]
432struct HumMainWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>);
433impl_concatenate_for_wrapper!(HumMainWeaponSpec);
434#[derive(Deserialize)]
435struct HumArmorLanternSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
436impl_concatenate_for_wrapper!(HumArmorLanternSpec);
437#[derive(Deserialize)]
438struct HumArmorGliderSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
439impl_concatenate_for_wrapper!(HumArmorGliderSpec);
440#[derive(Deserialize)]
441struct HumArmorHeadSpec(ArmorVoxSpecMap<(Species, BodyType, String), ArmorVoxSpec>);
442impl_concatenate_for_wrapper!(HumArmorHeadSpec);
443#[derive(Deserialize)]
444struct HumArmorTabardSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
445impl_concatenate_for_wrapper!(HumArmorTabardSpec);
446
447make_vox_spec!(
448    Body,
449    struct HumSpec {
450        color: HumColorSpec = "voxygen.voxel.humanoid_color_manifest",
451        head: HumHeadSpec = "voxygen.voxel.humanoid_head_manifest",
452        armor_shoulder: HumArmorShoulderSpec = "voxygen.voxel.humanoid_armor_shoulder_manifest",
453        armor_chest: HumArmorChestSpec = "voxygen.voxel.humanoid_armor_chest_manifest",
454        armor_hand: HumArmorHandSpec = "voxygen.voxel.humanoid_armor_hand_manifest",
455        armor_belt: HumArmorBeltSpec = "voxygen.voxel.humanoid_armor_belt_manifest",
456        armor_back: HumArmorBackSpec = "voxygen.voxel.humanoid_armor_back_manifest",
457        armor_pants: HumArmorPantsSpec = "voxygen.voxel.humanoid_armor_pants_manifest",
458        armor_foot: HumArmorFootSpec = "voxygen.voxel.humanoid_armor_foot_manifest",
459        main_weapon: HumMainWeaponSpec = "voxygen.voxel.biped_weapon_manifest",
460        armor_lantern: HumArmorLanternSpec = "voxygen.voxel.humanoid_lantern_manifest",
461        armor_glider: HumArmorGliderSpec = "voxygen.voxel.humanoid_glider_manifest",
462        armor_head: HumArmorHeadSpec = "voxygen.voxel.humanoid_armor_head_manifest",
463        // TODO: Add these.
464        /* tabard: HumArmorTabardSpec = "voxygen.voxel.humanoid_armor_tabard_manifest", */
465    },
466    |FigureKey {
467         body,
468         item_key: _,
469         extra,
470     },
471     spec| {
472        const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
473            third_person: None,
474            tool: None,
475            lantern: None,
476            glider: None,
477            hand: None,
478            foot: None,
479            head: None,
480        };
481
482        // TODO: This is bad code, maybe this method should return Option<_>
483        let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT);
484        let third_person = loadout.third_person.as_ref();
485        let tool = loadout.tool.as_ref();
486        let lantern = loadout.lantern.as_deref();
487        let glider = loadout.glider.as_deref();
488        let hand = loadout.hand.as_deref();
489        let foot = loadout.foot.as_deref();
490
491        let color = &spec.color.read().0;
492
493        [
494            third_person.map(|_| {
495                spec.head.read().0.mesh_head(
496                    body,
497                    color,
498                    spec.armor_head
499                        .read()
500                        .0
501                        .load_head(body, loadout.head.as_deref()),
502                )
503            }),
504            third_person.map(|loadout| {
505                spec.armor_chest
506                    .read()
507                    .0
508                    .mesh_chest(body, color, loadout.chest.as_deref())
509            }),
510            third_person.map(|loadout| {
511                spec.armor_belt
512                    .read()
513                    .0
514                    .mesh_belt(body, color, loadout.belt.as_deref())
515            }),
516            third_person.map(|loadout| {
517                spec.armor_back
518                    .read()
519                    .0
520                    .mesh_back(body, color, loadout.back.as_deref())
521            }),
522            third_person.map(|loadout| {
523                spec.armor_pants
524                    .read()
525                    .0
526                    .mesh_pants(body, color, loadout.pants.as_deref())
527            }),
528            Some(spec.armor_hand.read().0.mesh_left_hand(body, color, hand)),
529            Some(spec.armor_hand.read().0.mesh_right_hand(body, color, hand)),
530            Some(spec.armor_foot.read().0.mesh_left_foot(body, color, foot)),
531            Some(spec.armor_foot.read().0.mesh_right_foot(body, color, foot)),
532            third_person.map(|loadout| {
533                spec.armor_shoulder.read().0.mesh_left_shoulder(
534                    body,
535                    color,
536                    loadout.shoulder.as_deref(),
537                )
538            }),
539            third_person.map(|loadout| {
540                spec.armor_shoulder.read().0.mesh_right_shoulder(
541                    body,
542                    color,
543                    loadout.shoulder.as_deref(),
544                )
545            }),
546            Some(spec.armor_glider.read().0.mesh_glider(body, color, glider)),
547            tool.and_then(|tool| tool.active.as_ref())
548                .map(|tool| spec.main_weapon.read().0.mesh_main_weapon(tool, false)),
549            tool.and_then(|tool| tool.second.as_ref())
550                .map(|tool| spec.main_weapon.read().0.mesh_main_weapon(tool, true)),
551            Some(
552                spec.armor_lantern
553                    .read()
554                    .0
555                    .mesh_lantern(body, color, lantern),
556            ),
557            Some(mesh_hold()),
558        ]
559    },
560);
561
562// Shoulder
563impl HumArmorShoulderSpec {
564    fn mesh_shoulder(
565        &self,
566        body: &Body,
567        color_spec: &HumColorSpec,
568        shoulder: Option<&str>,
569        flipped: bool,
570    ) -> BoneMeshes {
571        let spec = if let Some(shoulder) = shoulder {
572            match self.0.map.get(shoulder) {
573                Some(spec) => spec,
574                None => {
575                    error!(?shoulder, "No shoulder specification exists");
576                    return load_mesh("not_found", Vec3::new(-3.0, -3.5, 0.1));
577                },
578            }
579        } else {
580            &self.0.default
581        };
582
583        let mut shoulder_segment = color_spec.color_segment(
584            if flipped {
585                graceful_load_mat_segment_flipped(&spec.left.vox_spec.0, spec.left.vox_spec.2)
586            } else {
587                graceful_load_mat_segment(&spec.right.vox_spec.0, spec.right.vox_spec.2)
588            },
589            body.species.skin_color(body.skin),
590            color_spec.hair_color(body.species, body.hair_color),
591            body.species.eye_color(body.eye_color),
592        );
593
594        // TODO: use this if we can
595        /*let mut offset = spec.vox_spec.1;
596        if flipped {
597            offset[0] = -(shoulder_segment.size().x as f32) - offset[0];
598        }*/
599        let offset = if flipped {
600            spec.left.vox_spec.1
601        } else {
602            spec.right.vox_spec.1
603        };
604
605        if let Some(color) = if flipped {
606            spec.left.color
607        } else {
608            spec.right.color
609        } {
610            let shoulder_color = Vec3::from(color);
611            shoulder_segment =
612                shoulder_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(shoulder_color)));
613        }
614
615        (shoulder_segment, Vec3::from(offset))
616    }
617
618    fn mesh_left_shoulder(
619        &self,
620        body: &Body,
621        color_spec: &HumColorSpec,
622        shoulder: Option<&str>,
623    ) -> BoneMeshes {
624        self.mesh_shoulder(body, color_spec, shoulder, true)
625    }
626
627    fn mesh_right_shoulder(
628        &self,
629        body: &Body,
630        color_spec: &HumColorSpec,
631        shoulder: Option<&str>,
632    ) -> BoneMeshes {
633        self.mesh_shoulder(body, color_spec, shoulder, false)
634    }
635}
636// Chest
637impl HumArmorChestSpec {
638    fn mesh_chest(
639        &self,
640        body: &Body,
641        color_spec: &HumColorSpec,
642        chest: Option<&str>,
643    ) -> BoneMeshes {
644        let spec = if let Some(chest) = chest {
645            match self.0.map.get(chest) {
646                Some(spec) => spec,
647                None => {
648                    error!(?chest, "No chest specification exists");
649                    return load_mesh("not_found", Vec3::new(-7.0, -3.5, 2.0));
650                },
651            }
652        } else {
653            &self.0.default
654        };
655
656        let color = |mat_segment| {
657            color_spec.color_segment(
658                mat_segment,
659                body.species.skin_color(body.skin),
660                color_spec.hair_color(body.species, body.hair_color),
661                body.species.eye_color(body.eye_color),
662            )
663        };
664
665        let bare_chest = graceful_load_mat_segment("armor.empty", DEFAULT_INDEX);
666
667        let mut chest_armor = graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2);
668
669        if let Some(color) = spec.color {
670            let chest_color = Vec3::from(color);
671            chest_armor = chest_armor.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(chest_color)));
672        }
673
674        let chest = DynaUnionizer::new()
675            .add(color(bare_chest), Vec3::new(0, 0, 0))
676            .add(color(chest_armor), Vec3::new(0, 0, 0))
677            .unify()
678            .0;
679
680        (chest, Vec3::from(spec.vox_spec.1))
681    }
682}
683// Hand
684impl HumArmorHandSpec {
685    fn mesh_hand(
686        &self,
687        body: &Body,
688        color_spec: &HumColorSpec,
689        hand: Option<&str>,
690        flipped: bool,
691    ) -> BoneMeshes {
692        let spec = if let Some(hand) = hand {
693            match self.0.map.get(hand) {
694                Some(spec) => spec,
695                None => {
696                    error!(?hand, "No hand specification exists");
697                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
698                },
699            }
700        } else {
701            &self.0.default
702        };
703
704        let mut hand_segment = color_spec.color_segment(
705            if flipped {
706                graceful_load_mat_segment_flipped(&spec.left.vox_spec.0, spec.left.vox_spec.2)
707            } else {
708                graceful_load_mat_segment(&spec.right.vox_spec.0, spec.right.vox_spec.2)
709            },
710            body.species.skin_color(body.skin),
711            color_spec.hair_color(body.species, body.hair_color),
712            body.species.eye_color(body.eye_color),
713        );
714
715        let offset = if flipped {
716            spec.left.vox_spec.1
717        } else {
718            spec.right.vox_spec.1
719        };
720
721        if let Some(color) = if flipped {
722            spec.left.color
723        } else {
724            spec.right.color
725        } {
726            let hand_color = Vec3::from(color);
727            hand_segment = hand_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(hand_color)));
728        }
729
730        (hand_segment, Vec3::from(offset))
731    }
732
733    fn mesh_left_hand(
734        &self,
735        body: &Body,
736        color_spec: &HumColorSpec,
737        hand: Option<&str>,
738    ) -> BoneMeshes {
739        self.mesh_hand(body, color_spec, hand, true)
740    }
741
742    fn mesh_right_hand(
743        &self,
744        body: &Body,
745        color_spec: &HumColorSpec,
746        hand: Option<&str>,
747    ) -> BoneMeshes {
748        self.mesh_hand(body, color_spec, hand, false)
749    }
750}
751// Belt
752impl HumArmorBeltSpec {
753    fn mesh_belt(&self, body: &Body, color_spec: &HumColorSpec, belt: Option<&str>) -> BoneMeshes {
754        let spec = if let Some(belt) = belt {
755            match self.0.map.get(belt) {
756                Some(spec) => spec,
757                None => {
758                    error!(?belt, "No belt specification exists");
759                    return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0));
760                },
761            }
762        } else {
763            &self.0.default
764        };
765
766        let mut belt_segment = color_spec.color_segment(
767            graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2),
768            body.species.skin_color(body.skin),
769            color_spec.hair_color(body.species, body.hair_color),
770            body.species.eye_color(body.eye_color),
771        );
772
773        if let Some(color) = spec.color {
774            let belt_color = Vec3::from(color);
775            belt_segment = belt_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(belt_color)));
776        }
777
778        (belt_segment, Vec3::from(spec.vox_spec.1))
779    }
780}
781// Cape
782impl HumArmorBackSpec {
783    fn mesh_back(&self, body: &Body, color_spec: &HumColorSpec, back: Option<&str>) -> BoneMeshes {
784        let spec = if let Some(back) = back {
785            match self.0.map.get(back) {
786                Some(spec) => spec,
787                None => {
788                    error!(?back, "No back specification exists");
789                    return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0));
790                },
791            }
792        } else {
793            &self.0.default
794        };
795
796        let mut back_segment = color_spec.color_segment(
797            graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2),
798            body.species.skin_color(body.skin),
799            color_spec.hair_color(body.species, body.hair_color),
800            body.species.eye_color(body.eye_color),
801        );
802        if let Some(color) = spec.color {
803            let back_color = Vec3::from(color);
804            back_segment = back_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(back_color)));
805        }
806
807        (back_segment, Vec3::from(spec.vox_spec.1))
808    }
809}
810// Legs
811impl HumArmorPantsSpec {
812    fn mesh_pants(
813        &self,
814        body: &Body,
815        color_spec: &HumColorSpec,
816        pants: Option<&str>,
817    ) -> BoneMeshes {
818        let spec = if let Some(pants) = pants {
819            match self.0.map.get(pants) {
820                Some(spec) => spec,
821                None => {
822                    error!(?pants, "No pants specification exists");
823                    return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0));
824                },
825            }
826        } else {
827            &self.0.default
828        };
829
830        let color = |mat_segment| {
831            color_spec.color_segment(
832                mat_segment,
833                body.species.skin_color(body.skin),
834                color_spec.hair_color(body.species, body.hair_color),
835                body.species.eye_color(body.eye_color),
836            )
837        };
838
839        let bare_pants = graceful_load_mat_segment("armor.empty", DEFAULT_INDEX);
840
841        let mut pants_armor = graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2);
842
843        if let Some(color) = spec.color {
844            let pants_color = Vec3::from(color);
845            pants_armor = pants_armor.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(pants_color)));
846        }
847
848        let pants = DynaUnionizer::new()
849            .add(color(bare_pants), Vec3::new(0, 0, 0))
850            .add(color(pants_armor), Vec3::new(0, 0, 0))
851            .unify()
852            .0;
853
854        (pants, Vec3::from(spec.vox_spec.1))
855    }
856}
857// Foot
858impl HumArmorFootSpec {
859    fn mesh_foot(
860        &self,
861        body: &Body,
862        color_spec: &HumColorSpec,
863        foot: Option<&str>,
864        flipped: bool,
865    ) -> BoneMeshes {
866        let spec = if let Some(foot) = foot {
867            match self.0.map.get(foot) {
868                Some(spec) => spec,
869                None => {
870                    error!(?foot, "No foot specification exists");
871                    return load_mesh("not_found", Vec3::new(-2.5, -3.5, -9.0));
872                },
873            }
874        } else {
875            &self.0.default
876        };
877
878        let mut foot_segment = color_spec.color_segment(
879            if flipped {
880                graceful_load_mat_segment_flipped(&spec.vox_spec.0, spec.vox_spec.2)
881            } else {
882                graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2)
883            },
884            body.species.skin_color(body.skin),
885            color_spec.hair_color(body.species, body.hair_color),
886            body.species.eye_color(body.eye_color),
887        );
888
889        if let Some(color) = spec.color {
890            let foot_color = Vec3::from(color);
891            foot_segment = foot_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(foot_color)));
892        }
893
894        (foot_segment, Vec3::from(spec.vox_spec.1))
895    }
896
897    fn mesh_left_foot(
898        &self,
899        body: &Body,
900        color_spec: &HumColorSpec,
901        foot: Option<&str>,
902    ) -> BoneMeshes {
903        self.mesh_foot(body, color_spec, foot, true)
904    }
905
906    fn mesh_right_foot(
907        &self,
908        body: &Body,
909        color_spec: &HumColorSpec,
910        foot: Option<&str>,
911    ) -> BoneMeshes {
912        self.mesh_foot(body, color_spec, foot, false)
913    }
914}
915
916impl HumMainWeaponSpec {
917    fn mesh_main_weapon(&self, tool: &ToolKey, flipped: bool) -> BoneMeshes {
918        let not_found = |tool: &ToolKey| {
919            error!(?tool, "No tool/weapon specification exists");
920            load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0))
921        };
922
923        let spec = match self.0.get(tool) {
924            Some(spec) => spec,
925            None => return not_found(tool),
926        };
927
928        let tool_kind_segment =
929            graceful_load_segment_flipped(&spec.vox_spec.0, flipped, spec.vox_spec.2);
930        let mut offset = Vec3::from(spec.vox_spec.1);
931
932        if flipped {
933            offset.x = 0.0 - offset.x - (tool_kind_segment.sz.x as f32);
934        }
935
936        (tool_kind_segment, offset)
937    }
938}
939
940// Lantern
941impl HumArmorLanternSpec {
942    fn mesh_lantern(
943        &self,
944        body: &Body,
945        color_spec: &HumColorSpec,
946        lantern: Option<&str>,
947    ) -> BoneMeshes {
948        let spec = if let Some(kind) = lantern {
949            match self.0.map.get(kind) {
950                Some(spec) => spec,
951                None => {
952                    error!(?kind, "No lantern specification exists");
953                    return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0));
954                },
955            }
956        } else {
957            &self.0.default
958        };
959
960        let mut lantern_segment = color_spec.color_segment(
961            graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2),
962            body.species.skin_color(body.skin),
963            color_spec.hair_color(body.species, body.hair_color),
964            body.species.eye_color(body.eye_color),
965        );
966        if let Some(color) = spec.color {
967            let lantern_color = Vec3::from(color);
968            lantern_segment =
969                lantern_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(lantern_color)));
970        }
971
972        (lantern_segment, Vec3::from(spec.vox_spec.1))
973    }
974}
975impl HumArmorHeadSpec {
976    fn load_head(&self, body: &Body, head: Option<&str>) -> Option<(Segment, Vec3<i32>)> {
977        if let Some(spec) = self
978            .0
979            .map
980            .get(&(body.species, body.body_type, head?.to_string()))
981        {
982            let segment = graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2);
983            let segment = if let Some(color) = spec.color {
984                let color = Vec3::from(color);
985                segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(color)))
986            } else {
987                segment
988            };
989            Some((segment, Vec3::<f32>::from(spec.vox_spec.1).as_()))
990        } else {
991            warn!("No specification for this head: {:?}", head);
992            None
993        }
994    }
995}
996
997impl HumArmorTabardSpec {
998    /// FIXME: Either use this, or remove it.
999    #[expect(dead_code)]
1000    fn mesh_tabard(
1001        &self,
1002        body: &Body,
1003        color_spec: &HumColorSpec,
1004        tabard: Option<&str>,
1005    ) -> BoneMeshes {
1006        let spec = if let Some(tabard) = tabard {
1007            match self.0.map.get(tabard) {
1008                Some(spec) => spec,
1009                None => {
1010                    error!(?tabard, "No tabard specification exists");
1011                    return load_mesh("not_found", Vec3::new(-5.0, -3.5, 1.0));
1012                },
1013            }
1014        } else {
1015            &self.0.default
1016        };
1017
1018        let color = |mat_segment| {
1019            color_spec.color_segment(
1020                mat_segment,
1021                body.species.skin_color(body.skin),
1022                color_spec.hair_color(body.species, body.hair_color),
1023                body.species.eye_color(body.eye_color),
1024            )
1025        };
1026
1027        let bare_tabard = graceful_load_mat_segment("armor.empty", DEFAULT_INDEX);
1028
1029        let mut tabard_armor = graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2);
1030
1031        if let Some(color) = spec.color {
1032            let tabard_color = Vec3::from(color);
1033            tabard_armor = tabard_armor.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(tabard_color)));
1034        }
1035
1036        let tabard = DynaUnionizer::new()
1037            .add(color(bare_tabard), Vec3::new(0, 0, 0))
1038            .add(color(tabard_armor), Vec3::new(0, 0, 0))
1039            .unify()
1040            .0;
1041
1042        (tabard, Vec3::from(spec.vox_spec.1))
1043    }
1044}
1045impl HumArmorGliderSpec {
1046    fn mesh_glider(
1047        &self,
1048        body: &Body,
1049        color_spec: &HumColorSpec,
1050        glider: Option<&str>,
1051    ) -> BoneMeshes {
1052        let spec = if let Some(kind) = glider {
1053            match self.0.map.get(kind) {
1054                Some(spec) => spec,
1055                None => {
1056                    error!(?kind, "No glider specification exists");
1057                    return load_mesh("not_found", Vec3::new(-4.0, -3.5, 2.0));
1058                },
1059            }
1060        } else {
1061            &self.0.default
1062        };
1063
1064        let mut glider_segment = color_spec.color_segment(
1065            graceful_load_mat_segment(&spec.vox_spec.0, spec.vox_spec.2),
1066            body.species.skin_color(body.skin),
1067            color_spec.hair_color(body.species, body.hair_color),
1068            body.species.eye_color(body.eye_color),
1069        );
1070        if let Some(color) = spec.color {
1071            let glider_color = Vec3::from(color);
1072            glider_segment =
1073                glider_segment.map_rgb(|rgb| recolor_grey(rgb, Rgb::from(glider_color)));
1074        }
1075
1076        (glider_segment, Vec3::from(spec.vox_spec.1))
1077    }
1078}
1079
1080fn mesh_hold() -> BoneMeshes {
1081    load_mesh(
1082        "weapon.projectile.simple-arrow",
1083        Vec3::new(-0.5, -6.0, -1.5),
1084    )
1085}
1086
1087//////
1088#[derive(Deserialize)]
1089struct QuadrupedSmallCentralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSCentralVoxSpec>);
1090impl_concatenate_for_wrapper!(QuadrupedSmallCentralSpec);
1091
1092#[derive(Deserialize, Default)]
1093#[serde(default)]
1094struct SidedQSCentralVoxSpec {
1095    head: QuadrupedSmallCentralSubSpec,
1096    chest: QuadrupedSmallCentralSubSpec,
1097    tail: QuadrupedSmallCentralSubSpec,
1098}
1099#[derive(Deserialize, Default)]
1100struct QuadrupedSmallCentralSubSpec {
1101    offset: [f32; 3], // Should be relative to initial origin
1102    central: VoxSimple,
1103    #[serde(default)]
1104    model_index: u32,
1105}
1106
1107#[derive(Deserialize)]
1108struct QuadrupedSmallLateralSpec(HashMap<(QSSpecies, QSBodyType), SidedQSLateralVoxSpec>);
1109impl_concatenate_for_wrapper!(QuadrupedSmallLateralSpec);
1110
1111#[derive(Deserialize, Default)]
1112#[serde(default)]
1113struct SidedQSLateralVoxSpec {
1114    left_front: QuadrupedSmallLateralSubSpec,
1115    right_front: QuadrupedSmallLateralSubSpec,
1116    left_back: QuadrupedSmallLateralSubSpec,
1117    right_back: QuadrupedSmallLateralSubSpec,
1118}
1119#[derive(Deserialize, Default)]
1120struct QuadrupedSmallLateralSubSpec {
1121    offset: [f32; 3], // Should be relative to initial origin
1122    lateral: VoxSimple,
1123    #[serde(default)]
1124    model_index: u32,
1125}
1126
1127make_vox_spec!(
1128    quadruped_small::Body,
1129    struct QuadrupedSmallSpec {
1130        central: QuadrupedSmallCentralSpec = "voxygen.voxel.quadruped_small_central_manifest",
1131        lateral: QuadrupedSmallLateralSpec = "voxygen.voxel.quadruped_small_lateral_manifest",
1132    },
1133    |FigureKey { body, extra, .. }, spec| {
1134        let third_person = extra
1135            .as_ref()
1136            .and_then(|loadout| loadout.third_person.as_ref());
1137
1138        [
1139            third_person.map(|_| {
1140                spec.central
1141                    .read()
1142                    .0
1143                    .mesh_head(body.species, body.body_type)
1144            }),
1145            Some(
1146                spec.central
1147                    .read()
1148                    .0
1149                    .mesh_chest(body.species, body.body_type),
1150            ),
1151            Some(
1152                spec.lateral
1153                    .read()
1154                    .0
1155                    .mesh_foot_fl(body.species, body.body_type),
1156            ),
1157            Some(
1158                spec.lateral
1159                    .read()
1160                    .0
1161                    .mesh_foot_fr(body.species, body.body_type),
1162            ),
1163            Some(
1164                spec.lateral
1165                    .read()
1166                    .0
1167                    .mesh_foot_bl(body.species, body.body_type),
1168            ),
1169            Some(
1170                spec.lateral
1171                    .read()
1172                    .0
1173                    .mesh_foot_br(body.species, body.body_type),
1174            ),
1175            Some(
1176                spec.central
1177                    .read()
1178                    .0
1179                    .mesh_tail(body.species, body.body_type),
1180            ),
1181            None,
1182            None,
1183            None,
1184            None,
1185            None,
1186            None,
1187            None,
1188            None,
1189            None,
1190        ]
1191    },
1192);
1193
1194impl QuadrupedSmallCentralSpec {
1195    fn mesh_head(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1196        let spec = match self.0.get(&(species, body_type)) {
1197            Some(spec) => spec,
1198            None => {
1199                error!(
1200                    "No head specification exists for the combination of {:?} and {:?}",
1201                    species, body_type
1202                );
1203                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1204            },
1205        };
1206        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
1207
1208        (central, Vec3::from(spec.head.offset))
1209    }
1210
1211    fn mesh_chest(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1212        let spec = match self.0.get(&(species, body_type)) {
1213            Some(spec) => spec,
1214            None => {
1215                error!(
1216                    "No chest specification exists for the combination of {:?} and {:?}",
1217                    species, body_type
1218                );
1219                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1220            },
1221        };
1222        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
1223
1224        (central, Vec3::from(spec.chest.offset))
1225    }
1226
1227    fn mesh_tail(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1228        let spec = match self.0.get(&(species, body_type)) {
1229            Some(spec) => spec,
1230            None => {
1231                error!(
1232                    "No tail specification exists for the combination of {:?} and {:?}",
1233                    species, body_type
1234                );
1235                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1236            },
1237        };
1238        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
1239
1240        (central, Vec3::from(spec.tail.offset))
1241    }
1242}
1243
1244impl QuadrupedSmallLateralSpec {
1245    fn mesh_foot_fl(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1246        let spec = match self.0.get(&(species, body_type)) {
1247            Some(spec) => spec,
1248            None => {
1249                error!(
1250                    "No leg specification exists for the combination of {:?} and {:?}",
1251                    species, body_type
1252                );
1253                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1254            },
1255        };
1256        let lateral = graceful_load_segment_flipped(
1257            &spec.left_front.lateral.0,
1258            true,
1259            spec.left_front.model_index,
1260        );
1261
1262        (lateral, Vec3::from(spec.left_front.offset))
1263    }
1264
1265    fn mesh_foot_fr(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1266        let spec = match self.0.get(&(species, body_type)) {
1267            Some(spec) => spec,
1268            None => {
1269                error!(
1270                    "No leg specification exists for the combination of {:?} and {:?}",
1271                    species, body_type
1272                );
1273                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1274            },
1275        };
1276        let lateral =
1277            graceful_load_segment(&spec.right_front.lateral.0, spec.right_front.model_index);
1278
1279        (lateral, Vec3::from(spec.right_front.offset))
1280    }
1281
1282    fn mesh_foot_bl(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1283        let spec = match self.0.get(&(species, body_type)) {
1284            Some(spec) => spec,
1285            None => {
1286                error!(
1287                    "No leg specification exists for the combination of {:?} and {:?}",
1288                    species, body_type
1289                );
1290                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1291            },
1292        };
1293        let lateral = graceful_load_segment_flipped(
1294            &spec.left_back.lateral.0,
1295            true,
1296            spec.left_back.model_index,
1297        );
1298
1299        (lateral, Vec3::from(spec.left_back.offset))
1300    }
1301
1302    fn mesh_foot_br(&self, species: QSSpecies, body_type: QSBodyType) -> BoneMeshes {
1303        let spec = match self.0.get(&(species, body_type)) {
1304            Some(spec) => spec,
1305            None => {
1306                error!(
1307                    "No leg specification exists for the combination of {:?} and {:?}",
1308                    species, body_type
1309                );
1310                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1311            },
1312        };
1313        let lateral =
1314            graceful_load_segment(&spec.right_back.lateral.0, spec.right_back.model_index);
1315
1316        (lateral, Vec3::from(spec.right_back.offset))
1317    }
1318}
1319
1320//////
1321#[derive(Deserialize)]
1322struct QuadrupedMediumCentralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMCentralVoxSpec>);
1323impl_concatenate_for_wrapper!(QuadrupedMediumCentralSpec);
1324
1325#[derive(Deserialize, Default)]
1326#[serde(default)]
1327struct SidedQMCentralVoxSpec {
1328    head: QuadrupedMediumCentralSubSpec,
1329    neck: QuadrupedMediumCentralSubSpec,
1330    jaw: QuadrupedMediumCentralSubSpec,
1331    ears: QuadrupedMediumCentralSubSpec,
1332    torso_front: QuadrupedMediumCentralSubSpec,
1333    torso_back: QuadrupedMediumCentralSubSpec,
1334    tail: QuadrupedMediumCentralSubSpec,
1335}
1336#[derive(Deserialize, Default)]
1337struct QuadrupedMediumCentralSubSpec {
1338    offset: [f32; 3], // Should be relative to initial origin
1339    central: VoxSimple,
1340    #[serde(default)]
1341    model_index: u32,
1342}
1343
1344#[derive(Deserialize)]
1345struct QuadrupedMediumLateralSpec(HashMap<(QMSpecies, QMBodyType), SidedQMLateralVoxSpec>);
1346impl_concatenate_for_wrapper!(QuadrupedMediumLateralSpec);
1347
1348#[derive(Deserialize, Default)]
1349#[serde(default)]
1350struct SidedQMLateralVoxSpec {
1351    leg_fl: QuadrupedMediumLateralSubSpec,
1352    leg_fr: QuadrupedMediumLateralSubSpec,
1353    leg_bl: QuadrupedMediumLateralSubSpec,
1354    leg_br: QuadrupedMediumLateralSubSpec,
1355    foot_fl: QuadrupedMediumLateralSubSpec,
1356    foot_fr: QuadrupedMediumLateralSubSpec,
1357    foot_bl: QuadrupedMediumLateralSubSpec,
1358    foot_br: QuadrupedMediumLateralSubSpec,
1359}
1360#[derive(Deserialize, Default)]
1361struct QuadrupedMediumLateralSubSpec {
1362    offset: [f32; 3], // Should be relative to initial origin
1363    lateral: VoxSimple,
1364    #[serde(default)]
1365    model_index: u32,
1366}
1367
1368make_vox_spec!(
1369    quadruped_medium::Body,
1370    struct QuadrupedMediumSpec {
1371        central: QuadrupedMediumCentralSpec = "voxygen.voxel.quadruped_medium_central_manifest",
1372        lateral: QuadrupedMediumLateralSpec = "voxygen.voxel.quadruped_medium_lateral_manifest",
1373    },
1374    |FigureKey { body, extra, .. }, spec| {
1375        let third_person = extra
1376            .as_ref()
1377            .and_then(|loadout| loadout.third_person.as_ref());
1378
1379        [
1380            third_person.map(|_| {
1381                spec.central
1382                    .read()
1383                    .0
1384                    .mesh_head(body.species, body.body_type)
1385            }),
1386            third_person.map(|_| {
1387                spec.central
1388                    .read()
1389                    .0
1390                    .mesh_neck(body.species, body.body_type)
1391            }),
1392            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
1393            Some(
1394                spec.central
1395                    .read()
1396                    .0
1397                    .mesh_tail(body.species, body.body_type),
1398            ),
1399            Some(
1400                spec.central
1401                    .read()
1402                    .0
1403                    .mesh_torso_front(body.species, body.body_type),
1404            ),
1405            Some(
1406                spec.central
1407                    .read()
1408                    .0
1409                    .mesh_torso_back(body.species, body.body_type),
1410            ),
1411            third_person.map(|_| {
1412                spec.central
1413                    .read()
1414                    .0
1415                    .mesh_ears(body.species, body.body_type)
1416            }),
1417            Some(
1418                spec.lateral
1419                    .read()
1420                    .0
1421                    .mesh_leg_fl(body.species, body.body_type),
1422            ),
1423            Some(
1424                spec.lateral
1425                    .read()
1426                    .0
1427                    .mesh_leg_fr(body.species, body.body_type),
1428            ),
1429            Some(
1430                spec.lateral
1431                    .read()
1432                    .0
1433                    .mesh_leg_bl(body.species, body.body_type),
1434            ),
1435            Some(
1436                spec.lateral
1437                    .read()
1438                    .0
1439                    .mesh_leg_br(body.species, body.body_type),
1440            ),
1441            Some(
1442                spec.lateral
1443                    .read()
1444                    .0
1445                    .mesh_foot_fl(body.species, body.body_type),
1446            ),
1447            Some(
1448                spec.lateral
1449                    .read()
1450                    .0
1451                    .mesh_foot_fr(body.species, body.body_type),
1452            ),
1453            Some(
1454                spec.lateral
1455                    .read()
1456                    .0
1457                    .mesh_foot_bl(body.species, body.body_type),
1458            ),
1459            Some(
1460                spec.lateral
1461                    .read()
1462                    .0
1463                    .mesh_foot_br(body.species, body.body_type),
1464            ),
1465            None,
1466        ]
1467    }
1468);
1469
1470impl QuadrupedMediumCentralSpec {
1471    fn mesh_head(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1472        let spec = match self.0.get(&(species, body_type)) {
1473            Some(spec) => spec,
1474            None => {
1475                error!(
1476                    "No head specification exists for the combination of {:?} and {:?}",
1477                    species, body_type
1478                );
1479                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1480            },
1481        };
1482        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
1483
1484        (central, Vec3::from(spec.head.offset))
1485    }
1486
1487    fn mesh_neck(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1488        let spec = match self.0.get(&(species, body_type)) {
1489            Some(spec) => spec,
1490            None => {
1491                error!(
1492                    "No neck specification exists for the combination of {:?} and {:?}",
1493                    species, body_type
1494                );
1495                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1496            },
1497        };
1498        let central = graceful_load_segment(&spec.neck.central.0, spec.neck.model_index);
1499
1500        (central, Vec3::from(spec.neck.offset))
1501    }
1502
1503    fn mesh_jaw(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1504        let spec = match self.0.get(&(species, body_type)) {
1505            Some(spec) => spec,
1506            None => {
1507                error!(
1508                    "No jaw specification exists for the combination of {:?} and {:?}",
1509                    species, body_type
1510                );
1511                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1512            },
1513        };
1514        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
1515
1516        (central, Vec3::from(spec.jaw.offset))
1517    }
1518
1519    fn mesh_ears(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1520        let spec = match self.0.get(&(species, body_type)) {
1521            Some(spec) => spec,
1522            None => {
1523                error!(
1524                    "No ears specification exists for the combination of {:?} and {:?}",
1525                    species, body_type
1526                );
1527                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1528            },
1529        };
1530        let central = graceful_load_segment(&spec.ears.central.0, spec.ears.model_index);
1531
1532        (central, Vec3::from(spec.ears.offset))
1533    }
1534
1535    fn mesh_torso_front(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1536        let spec = match self.0.get(&(species, body_type)) {
1537            Some(spec) => spec,
1538            None => {
1539                error!(
1540                    "No torso specification exists for the combination of {:?} and {:?}",
1541                    species, body_type
1542                );
1543                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1544            },
1545        };
1546        let central =
1547            graceful_load_segment(&spec.torso_front.central.0, spec.torso_front.model_index);
1548
1549        (central, Vec3::from(spec.torso_front.offset))
1550    }
1551
1552    fn mesh_torso_back(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1553        let spec = match self.0.get(&(species, body_type)) {
1554            Some(spec) => spec,
1555            None => {
1556                error!(
1557                    "No torso specification exists for the combination of {:?} and {:?}",
1558                    species, body_type
1559                );
1560                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1561            },
1562        };
1563        let central =
1564            graceful_load_segment(&spec.torso_back.central.0, spec.torso_back.model_index);
1565
1566        (central, Vec3::from(spec.torso_back.offset))
1567    }
1568
1569    fn mesh_tail(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1570        let spec = match self.0.get(&(species, body_type)) {
1571            Some(spec) => spec,
1572            None => {
1573                error!(
1574                    "No tail specification exists for the combination of {:?} and {:?}",
1575                    species, body_type
1576                );
1577                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1578            },
1579        };
1580        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
1581
1582        (central, Vec3::from(spec.tail.offset))
1583    }
1584}
1585
1586impl QuadrupedMediumLateralSpec {
1587    fn mesh_leg_fl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1588        let spec = match self.0.get(&(species, body_type)) {
1589            Some(spec) => spec,
1590            None => {
1591                error!(
1592                    "No leg specification exists for the combination of {:?} and {:?}",
1593                    species, body_type
1594                );
1595                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1596            },
1597        };
1598        let lateral =
1599            graceful_load_segment_flipped(&spec.leg_fl.lateral.0, true, spec.leg_fl.model_index);
1600
1601        (lateral, Vec3::from(spec.leg_fl.offset))
1602    }
1603
1604    fn mesh_leg_fr(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1605        let spec = match self.0.get(&(species, body_type)) {
1606            Some(spec) => spec,
1607            None => {
1608                error!(
1609                    "No leg specification exists for the combination of {:?} and {:?}",
1610                    species, body_type
1611                );
1612                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1613            },
1614        };
1615        let lateral = graceful_load_segment(&spec.leg_fr.lateral.0, spec.leg_fr.model_index);
1616
1617        (lateral, Vec3::from(spec.leg_fr.offset))
1618    }
1619
1620    fn mesh_leg_bl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1621        let spec = match self.0.get(&(species, body_type)) {
1622            Some(spec) => spec,
1623            None => {
1624                error!(
1625                    "No leg specification exists for the combination of {:?} and {:?}",
1626                    species, body_type
1627                );
1628                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1629            },
1630        };
1631        let lateral =
1632            graceful_load_segment_flipped(&spec.leg_bl.lateral.0, true, spec.leg_bl.model_index);
1633
1634        (lateral, Vec3::from(spec.leg_bl.offset))
1635    }
1636
1637    fn mesh_leg_br(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1638        let spec = match self.0.get(&(species, body_type)) {
1639            Some(spec) => spec,
1640            None => {
1641                error!(
1642                    "No leg specification exists for the combination of {:?} and {:?}",
1643                    species, body_type
1644                );
1645                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1646            },
1647        };
1648        let lateral = graceful_load_segment(&spec.leg_br.lateral.0, spec.leg_br.model_index);
1649
1650        (lateral, Vec3::from(spec.leg_br.offset))
1651    }
1652
1653    fn mesh_foot_fl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1654        let spec = match self.0.get(&(species, body_type)) {
1655            Some(spec) => spec,
1656            None => {
1657                error!(
1658                    "No foot specification exists for the combination of {:?} and {:?}",
1659                    species, body_type
1660                );
1661                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1662            },
1663        };
1664        let lateral =
1665            graceful_load_segment_flipped(&spec.foot_fl.lateral.0, true, spec.foot_fl.model_index);
1666
1667        (lateral, Vec3::from(spec.foot_fl.offset))
1668    }
1669
1670    fn mesh_foot_fr(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1671        let spec = match self.0.get(&(species, body_type)) {
1672            Some(spec) => spec,
1673            None => {
1674                error!(
1675                    "No foot specification exists for the combination of {:?} and {:?}",
1676                    species, body_type
1677                );
1678                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1679            },
1680        };
1681        let lateral = graceful_load_segment(&spec.foot_fr.lateral.0, spec.foot_fr.model_index);
1682
1683        (lateral, Vec3::from(spec.foot_fr.offset))
1684    }
1685
1686    fn mesh_foot_bl(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1687        let spec = match self.0.get(&(species, body_type)) {
1688            Some(spec) => spec,
1689            None => {
1690                error!(
1691                    "No foot specification exists for the combination of {:?} and {:?}",
1692                    species, body_type
1693                );
1694                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1695            },
1696        };
1697        let lateral =
1698            graceful_load_segment_flipped(&spec.foot_bl.lateral.0, true, spec.foot_bl.model_index);
1699
1700        (lateral, Vec3::from(spec.foot_bl.offset))
1701    }
1702
1703    fn mesh_foot_br(&self, species: QMSpecies, body_type: QMBodyType) -> BoneMeshes {
1704        let spec = match self.0.get(&(species, body_type)) {
1705            Some(spec) => spec,
1706            None => {
1707                error!(
1708                    "No foot specification exists for the combination of {:?} and {:?}",
1709                    species, body_type
1710                );
1711                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1712            },
1713        };
1714        let lateral = graceful_load_segment(&spec.foot_br.lateral.0, spec.foot_br.model_index);
1715
1716        (lateral, Vec3::from(spec.foot_br.offset))
1717    }
1718}
1719
1720//////
1721#[derive(Deserialize)]
1722struct BirdMediumCentralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMCentralVoxSpec>);
1723impl_concatenate_for_wrapper!(BirdMediumCentralSpec);
1724
1725#[derive(Deserialize, Default)]
1726#[serde(default)]
1727struct SidedBMCentralVoxSpec {
1728    head: BirdMediumCentralSubSpec,
1729    chest: BirdMediumCentralSubSpec,
1730    tail: BirdMediumCentralSubSpec,
1731}
1732#[derive(Deserialize, Default)]
1733struct BirdMediumCentralSubSpec {
1734    offset: [f32; 3], // Should be relative to initial origin
1735    central: VoxSimple,
1736    #[serde(default)]
1737    model_index: u32,
1738}
1739
1740#[derive(Deserialize)]
1741struct BirdMediumLateralSpec(HashMap<(BMSpecies, BMBodyType), SidedBMLateralVoxSpec>);
1742impl_concatenate_for_wrapper!(BirdMediumLateralSpec);
1743
1744#[derive(Deserialize, Default)]
1745#[serde(default)]
1746struct SidedBMLateralVoxSpec {
1747    wing_in_l: BirdMediumLateralSubSpec,
1748    wing_in_r: BirdMediumLateralSubSpec,
1749    wing_out_l: BirdMediumLateralSubSpec,
1750    wing_out_r: BirdMediumLateralSubSpec,
1751    leg_l: BirdMediumLateralSubSpec,
1752    leg_r: BirdMediumLateralSubSpec,
1753}
1754#[derive(Deserialize, Default)]
1755struct BirdMediumLateralSubSpec {
1756    offset: [f32; 3], // Should be relative to initial origin
1757    lateral: VoxSimple,
1758    #[serde(default)]
1759    model_index: u32,
1760}
1761
1762make_vox_spec!(
1763    bird_medium::Body,
1764    struct BirdMediumSpec {
1765        central: BirdMediumCentralSpec = "voxygen.voxel.bird_medium_central_manifest",
1766        lateral: BirdMediumLateralSpec = "voxygen.voxel.bird_medium_lateral_manifest",
1767    },
1768    |FigureKey { body, extra, .. }, spec| {
1769        let third_person = extra
1770            .as_ref()
1771            .and_then(|loadout| loadout.third_person.as_ref());
1772
1773        [
1774            third_person.map(|_| {
1775                spec.central
1776                    .read()
1777                    .0
1778                    .mesh_head(body.species, body.body_type)
1779            }),
1780            Some(
1781                spec.central
1782                    .read()
1783                    .0
1784                    .mesh_chest(body.species, body.body_type),
1785            ),
1786            Some(
1787                spec.central
1788                    .read()
1789                    .0
1790                    .mesh_tail(body.species, body.body_type),
1791            ),
1792            Some(
1793                spec.lateral
1794                    .read()
1795                    .0
1796                    .mesh_wing_in_l(body.species, body.body_type),
1797            ),
1798            Some(
1799                spec.lateral
1800                    .read()
1801                    .0
1802                    .mesh_wing_in_r(body.species, body.body_type),
1803            ),
1804            Some(
1805                spec.lateral
1806                    .read()
1807                    .0
1808                    .mesh_wing_out_l(body.species, body.body_type),
1809            ),
1810            Some(
1811                spec.lateral
1812                    .read()
1813                    .0
1814                    .mesh_wing_out_r(body.species, body.body_type),
1815            ),
1816            Some(
1817                spec.lateral
1818                    .read()
1819                    .0
1820                    .mesh_leg_l(body.species, body.body_type),
1821            ),
1822            Some(
1823                spec.lateral
1824                    .read()
1825                    .0
1826                    .mesh_leg_r(body.species, body.body_type),
1827            ),
1828            None,
1829            None,
1830            None,
1831            None,
1832            None,
1833            None,
1834            None,
1835        ]
1836    },
1837);
1838
1839impl BirdMediumCentralSpec {
1840    fn mesh_head(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1841        let spec = match self.0.get(&(species, body_type)) {
1842            Some(spec) => spec,
1843            None => {
1844                error!(
1845                    "No head specification exists for the combination of {:?} and {:?}",
1846                    species, body_type
1847                );
1848                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1849            },
1850        };
1851        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
1852
1853        (central, Vec3::from(spec.head.offset))
1854    }
1855
1856    fn mesh_chest(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1857        let spec = match self.0.get(&(species, body_type)) {
1858            Some(spec) => spec,
1859            None => {
1860                error!(
1861                    "No chest specification exists for the combination of {:?} and {:?}",
1862                    species, body_type
1863                );
1864                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1865            },
1866        };
1867        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
1868
1869        (central, Vec3::from(spec.chest.offset))
1870    }
1871
1872    fn mesh_tail(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1873        let spec = match self.0.get(&(species, body_type)) {
1874            Some(spec) => spec,
1875            None => {
1876                error!(
1877                    "No tail specification exists for the combination of {:?} and {:?}",
1878                    species, body_type
1879                );
1880                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1881            },
1882        };
1883        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
1884
1885        (central, Vec3::from(spec.tail.offset))
1886    }
1887}
1888impl BirdMediumLateralSpec {
1889    fn mesh_wing_in_l(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1890        let spec = match self.0.get(&(species, body_type)) {
1891            Some(spec) => spec,
1892            None => {
1893                error!(
1894                    "No wing in in left specification exists for the combination of {:?} and {:?}",
1895                    species, body_type
1896                );
1897                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1898            },
1899        };
1900        let lateral = graceful_load_segment_flipped(
1901            &spec.wing_in_l.lateral.0,
1902            true,
1903            spec.wing_in_l.model_index,
1904        );
1905
1906        (lateral, Vec3::from(spec.wing_in_l.offset))
1907    }
1908
1909    fn mesh_wing_in_r(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1910        let spec = match self.0.get(&(species, body_type)) {
1911            Some(spec) => spec,
1912            None => {
1913                error!(
1914                    "No wing in right specification exists for the combination of {:?} and {:?}",
1915                    species, body_type
1916                );
1917                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1918            },
1919        };
1920        let lateral = graceful_load_segment(&spec.wing_in_r.lateral.0, spec.wing_in_r.model_index);
1921
1922        (lateral, Vec3::from(spec.wing_in_r.offset))
1923    }
1924
1925    fn mesh_wing_out_l(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1926        let spec = match self.0.get(&(species, body_type)) {
1927            Some(spec) => spec,
1928            None => {
1929                error!(
1930                    "No wing out specification exists for the combination of {:?} and {:?}",
1931                    species, body_type
1932                );
1933                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1934            },
1935        };
1936        let lateral = graceful_load_segment_flipped(
1937            &spec.wing_out_l.lateral.0,
1938            true,
1939            spec.wing_out_l.model_index,
1940        );
1941
1942        (lateral, Vec3::from(spec.wing_out_l.offset))
1943    }
1944
1945    fn mesh_wing_out_r(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1946        let spec = match self.0.get(&(species, body_type)) {
1947            Some(spec) => spec,
1948            None => {
1949                error!(
1950                    "No wing out specification exists for the combination of {:?} and {:?}",
1951                    species, body_type
1952                );
1953                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1954            },
1955        };
1956        let lateral =
1957            graceful_load_segment(&spec.wing_out_r.lateral.0, spec.wing_out_r.model_index);
1958
1959        (lateral, Vec3::from(spec.wing_out_r.offset))
1960    }
1961
1962    fn mesh_leg_l(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1963        let spec = match self.0.get(&(species, body_type)) {
1964            Some(spec) => spec,
1965            None => {
1966                error!(
1967                    "No leg specification exists for the combination of {:?} and {:?}",
1968                    species, body_type
1969                );
1970                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1971            },
1972        };
1973        let lateral =
1974            graceful_load_segment_flipped(&spec.leg_l.lateral.0, true, spec.leg_l.model_index);
1975
1976        (lateral, Vec3::from(spec.leg_l.offset))
1977    }
1978
1979    fn mesh_leg_r(&self, species: BMSpecies, body_type: BMBodyType) -> BoneMeshes {
1980        let spec = match self.0.get(&(species, body_type)) {
1981            Some(spec) => spec,
1982            None => {
1983                error!(
1984                    "No leg specification exists for the combination of {:?} and {:?}",
1985                    species, body_type
1986                );
1987                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
1988            },
1989        };
1990        let lateral = graceful_load_segment(&spec.leg_r.lateral.0, spec.leg_r.model_index);
1991
1992        (lateral, Vec3::from(spec.leg_r.offset))
1993    }
1994}
1995
1996//////
1997#[derive(Deserialize)]
1998struct TheropodCentralSpec(HashMap<(TSpecies, TBodyType), SidedTCentralVoxSpec>);
1999impl_concatenate_for_wrapper!(TheropodCentralSpec);
2000
2001#[derive(Deserialize, Default)]
2002#[serde(default)]
2003struct SidedTCentralVoxSpec {
2004    head: TheropodCentralSubSpec,
2005    jaw: TheropodCentralSubSpec,
2006    neck: TheropodCentralSubSpec,
2007    chest_front: TheropodCentralSubSpec,
2008    chest_back: TheropodCentralSubSpec,
2009    tail_front: TheropodCentralSubSpec,
2010    tail_back: TheropodCentralSubSpec,
2011}
2012#[derive(Deserialize, Default)]
2013struct TheropodCentralSubSpec {
2014    offset: [f32; 3], // Should be relative to initial origin
2015    central: VoxSimple,
2016    #[serde(default)]
2017    model_index: u32,
2018}
2019#[derive(Deserialize)]
2020struct TheropodLateralSpec(HashMap<(TSpecies, TBodyType), SidedTLateralVoxSpec>);
2021impl_concatenate_for_wrapper!(TheropodLateralSpec);
2022
2023#[derive(Deserialize, Default)]
2024#[serde(default)]
2025struct SidedTLateralVoxSpec {
2026    hand_l: TheropodLateralSubSpec,
2027    hand_r: TheropodLateralSubSpec,
2028    leg_l: TheropodLateralSubSpec,
2029    leg_r: TheropodLateralSubSpec,
2030    foot_l: TheropodLateralSubSpec,
2031    foot_r: TheropodLateralSubSpec,
2032}
2033#[derive(Deserialize, Default)]
2034struct TheropodLateralSubSpec {
2035    offset: [f32; 3], // Should be relative to initial origin
2036    lateral: VoxSimple,
2037    #[serde(default)]
2038    model_index: u32,
2039}
2040make_vox_spec!(
2041    theropod::Body,
2042    struct TheropodSpec {
2043        central: TheropodCentralSpec = "voxygen.voxel.theropod_central_manifest",
2044        lateral: TheropodLateralSpec = "voxygen.voxel.theropod_lateral_manifest",
2045    },
2046    |FigureKey { body, extra, .. }, spec| {
2047        let third_person = extra
2048            .as_ref()
2049            .and_then(|loadout| loadout.third_person.as_ref());
2050
2051        [
2052            third_person.map(|_| {
2053                spec.central
2054                    .read()
2055                    .0
2056                    .mesh_head(body.species, body.body_type)
2057            }),
2058            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
2059            Some(
2060                spec.central
2061                    .read()
2062                    .0
2063                    .mesh_neck(body.species, body.body_type),
2064            ),
2065            Some(
2066                spec.central
2067                    .read()
2068                    .0
2069                    .mesh_chest_front(body.species, body.body_type),
2070            ),
2071            Some(
2072                spec.central
2073                    .read()
2074                    .0
2075                    .mesh_chest_back(body.species, body.body_type),
2076            ),
2077            Some(
2078                spec.central
2079                    .read()
2080                    .0
2081                    .mesh_tail_front(body.species, body.body_type),
2082            ),
2083            Some(
2084                spec.central
2085                    .read()
2086                    .0
2087                    .mesh_tail_back(body.species, body.body_type),
2088            ),
2089            Some(
2090                spec.lateral
2091                    .read()
2092                    .0
2093                    .mesh_hand_l(body.species, body.body_type),
2094            ),
2095            Some(
2096                spec.lateral
2097                    .read()
2098                    .0
2099                    .mesh_hand_r(body.species, body.body_type),
2100            ),
2101            Some(
2102                spec.lateral
2103                    .read()
2104                    .0
2105                    .mesh_leg_l(body.species, body.body_type),
2106            ),
2107            Some(
2108                spec.lateral
2109                    .read()
2110                    .0
2111                    .mesh_leg_r(body.species, body.body_type),
2112            ),
2113            Some(
2114                spec.lateral
2115                    .read()
2116                    .0
2117                    .mesh_foot_l(body.species, body.body_type),
2118            ),
2119            Some(
2120                spec.lateral
2121                    .read()
2122                    .0
2123                    .mesh_foot_r(body.species, body.body_type),
2124            ),
2125            None,
2126            None,
2127            None,
2128        ]
2129    },
2130);
2131
2132impl TheropodCentralSpec {
2133    fn mesh_head(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2134        let spec = match self.0.get(&(species, body_type)) {
2135            Some(spec) => spec,
2136            None => {
2137                error!(
2138                    "No head specification exists for the combination of {:?} and {:?}",
2139                    species, body_type
2140                );
2141                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2142            },
2143        };
2144        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
2145
2146        (central, Vec3::from(spec.head.offset))
2147    }
2148
2149    fn mesh_jaw(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2150        let spec = match self.0.get(&(species, body_type)) {
2151            Some(spec) => spec,
2152            None => {
2153                error!(
2154                    "No jaw specification exists for the combination of {:?} and {:?}",
2155                    species, body_type
2156                );
2157                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2158            },
2159        };
2160        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
2161
2162        (central, Vec3::from(spec.jaw.offset))
2163    }
2164
2165    fn mesh_neck(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2166        let spec = match self.0.get(&(species, body_type)) {
2167            Some(spec) => spec,
2168            None => {
2169                error!(
2170                    "No jaw specification exists for the combination of {:?} and {:?}",
2171                    species, body_type
2172                );
2173                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2174            },
2175        };
2176        let central = graceful_load_segment(&spec.neck.central.0, spec.neck.model_index);
2177
2178        (central, Vec3::from(spec.neck.offset))
2179    }
2180
2181    fn mesh_chest_front(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2182        let spec = match self.0.get(&(species, body_type)) {
2183            Some(spec) => spec,
2184            None => {
2185                error!(
2186                    "No front chest specification exists for the combination of {:?} and {:?}",
2187                    species, body_type
2188                );
2189                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2190            },
2191        };
2192        let central =
2193            graceful_load_segment(&spec.chest_front.central.0, spec.chest_front.model_index);
2194
2195        (central, Vec3::from(spec.chest_front.offset))
2196    }
2197
2198    fn mesh_chest_back(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2199        let spec = match self.0.get(&(species, body_type)) {
2200            Some(spec) => spec,
2201            None => {
2202                error!(
2203                    "No back chest specification exists for the combination of {:?} and {:?}",
2204                    species, body_type
2205                );
2206                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2207            },
2208        };
2209        let central =
2210            graceful_load_segment(&spec.chest_back.central.0, spec.chest_back.model_index);
2211
2212        (central, Vec3::from(spec.chest_back.offset))
2213    }
2214
2215    fn mesh_tail_front(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2216        let spec = match self.0.get(&(species, body_type)) {
2217            Some(spec) => spec,
2218            None => {
2219                error!(
2220                    "No front tail specification exists for the combination of {:?} and {:?}",
2221                    species, body_type
2222                );
2223                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2224            },
2225        };
2226        let central =
2227            graceful_load_segment(&spec.tail_front.central.0, spec.tail_front.model_index);
2228
2229        (central, Vec3::from(spec.tail_front.offset))
2230    }
2231
2232    fn mesh_tail_back(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2233        let spec = match self.0.get(&(species, body_type)) {
2234            Some(spec) => spec,
2235            None => {
2236                error!(
2237                    "No back tail specification exists for the combination of {:?} and {:?}",
2238                    species, body_type
2239                );
2240                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2241            },
2242        };
2243        let central = graceful_load_segment(&spec.tail_back.central.0, spec.tail_back.model_index);
2244
2245        (central, Vec3::from(spec.tail_back.offset))
2246    }
2247}
2248impl TheropodLateralSpec {
2249    fn mesh_hand_l(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2250        let spec = match self.0.get(&(species, body_type)) {
2251            Some(spec) => spec,
2252            None => {
2253                error!(
2254                    "No left hand specification exists for the combination of {:?} and {:?}",
2255                    species, body_type
2256                );
2257                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2258            },
2259        };
2260        let lateral =
2261            graceful_load_segment_flipped(&spec.hand_l.lateral.0, true, spec.hand_l.model_index);
2262
2263        (lateral, Vec3::from(spec.hand_l.offset))
2264    }
2265
2266    fn mesh_hand_r(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2267        let spec = match self.0.get(&(species, body_type)) {
2268            Some(spec) => spec,
2269            None => {
2270                error!(
2271                    "No right hand specification exists for the combination of {:?} and {:?}",
2272                    species, body_type
2273                );
2274                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2275            },
2276        };
2277        let lateral = graceful_load_segment(&spec.hand_r.lateral.0, spec.hand_r.model_index);
2278
2279        (lateral, Vec3::from(spec.hand_r.offset))
2280    }
2281
2282    fn mesh_leg_l(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2283        let spec = match self.0.get(&(species, body_type)) {
2284            Some(spec) => spec,
2285            None => {
2286                error!(
2287                    "No left leg specification exists for the combination of {:?} and {:?}",
2288                    species, body_type
2289                );
2290                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2291            },
2292        };
2293        let lateral =
2294            graceful_load_segment_flipped(&spec.leg_l.lateral.0, true, spec.leg_l.model_index);
2295
2296        (lateral, Vec3::from(spec.leg_l.offset))
2297    }
2298
2299    fn mesh_leg_r(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2300        let spec = match self.0.get(&(species, body_type)) {
2301            Some(spec) => spec,
2302            None => {
2303                error!(
2304                    "No right leg specification exists for the combination of {:?} and {:?}",
2305                    species, body_type
2306                );
2307                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2308            },
2309        };
2310        let lateral = graceful_load_segment(&spec.leg_r.lateral.0, spec.leg_r.model_index);
2311
2312        (lateral, Vec3::from(spec.leg_r.offset))
2313    }
2314
2315    fn mesh_foot_l(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2316        let spec = match self.0.get(&(species, body_type)) {
2317            Some(spec) => spec,
2318            None => {
2319                error!(
2320                    "No left foot specification exists for the combination of {:?} and {:?}",
2321                    species, body_type
2322                );
2323                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2324            },
2325        };
2326        let lateral =
2327            graceful_load_segment_flipped(&spec.foot_l.lateral.0, true, spec.foot_l.model_index);
2328
2329        (lateral, Vec3::from(spec.foot_l.offset))
2330    }
2331
2332    fn mesh_foot_r(&self, species: TSpecies, body_type: TBodyType) -> BoneMeshes {
2333        let spec = match self.0.get(&(species, body_type)) {
2334            Some(spec) => spec,
2335            None => {
2336                error!(
2337                    "No right foot specification exists for the combination of {:?} and {:?}",
2338                    species, body_type
2339                );
2340                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2341            },
2342        };
2343        let lateral = graceful_load_segment(&spec.foot_r.lateral.0, spec.foot_r.model_index);
2344
2345        (lateral, Vec3::from(spec.foot_r.offset))
2346    }
2347}
2348
2349//////
2350#[derive(Deserialize)]
2351struct ArthropodCentralSpec(HashMap<(ASpecies, ABodyType), SidedACentralVoxSpec>);
2352impl_concatenate_for_wrapper!(ArthropodCentralSpec);
2353
2354#[derive(Deserialize, Default)]
2355#[serde(default)]
2356struct SidedACentralVoxSpec {
2357    head: ArthropodCentralSubSpec,
2358    chest: ArthropodCentralSubSpec,
2359}
2360#[derive(Deserialize, Default)]
2361struct ArthropodCentralSubSpec {
2362    offset: [f32; 3], // Should be relative to initial origin
2363    central: VoxSimple,
2364    #[serde(default)]
2365    model_index: u32,
2366}
2367#[derive(Deserialize)]
2368struct ArthropodLateralSpec(HashMap<(ASpecies, ABodyType), SidedALateralVoxSpec>);
2369impl_concatenate_for_wrapper!(ArthropodLateralSpec);
2370
2371#[derive(Deserialize, Default)]
2372#[serde(default)]
2373struct SidedALateralVoxSpec {
2374    mandible_l: ArthropodLateralSubSpec,
2375    mandible_r: ArthropodLateralSubSpec,
2376    wing_fl: ArthropodLateralSubSpec,
2377    wing_fr: ArthropodLateralSubSpec,
2378    wing_bl: ArthropodLateralSubSpec,
2379    wing_br: ArthropodLateralSubSpec,
2380    leg_fl: ArthropodLateralSubSpec,
2381    leg_fr: ArthropodLateralSubSpec,
2382    leg_fcl: ArthropodLateralSubSpec,
2383    leg_fcr: ArthropodLateralSubSpec,
2384    leg_bcl: ArthropodLateralSubSpec,
2385    leg_bcr: ArthropodLateralSubSpec,
2386    leg_bl: ArthropodLateralSubSpec,
2387    leg_br: ArthropodLateralSubSpec,
2388}
2389#[derive(Deserialize, Default)]
2390struct ArthropodLateralSubSpec {
2391    offset: [f32; 3], // Should be relative to initial origin
2392    lateral: VoxSimple,
2393    #[serde(default)]
2394    model_index: u32,
2395}
2396make_vox_spec!(
2397    arthropod::Body,
2398    struct ArthropodSpec {
2399        central: ArthropodCentralSpec = "voxygen.voxel.arthropod_central_manifest",
2400        lateral: ArthropodLateralSpec = "voxygen.voxel.arthropod_lateral_manifest",
2401    },
2402    |FigureKey { body, extra, .. }, spec| {
2403        let third_person = extra
2404            .as_ref()
2405            .and_then(|loadout| loadout.third_person.as_ref());
2406
2407        [
2408            third_person.map(|_| {
2409                spec.central
2410                    .read()
2411                    .0
2412                    .mesh_head(body.species, body.body_type)
2413            }),
2414            Some(
2415                spec.central
2416                    .read()
2417                    .0
2418                    .mesh_chest(body.species, body.body_type),
2419            ),
2420            third_person.map(|_| {
2421                spec.lateral
2422                    .read()
2423                    .0
2424                    .mesh_mandible_l(body.species, body.body_type)
2425            }),
2426            third_person.map(|_| {
2427                spec.lateral
2428                    .read()
2429                    .0
2430                    .mesh_mandible_r(body.species, body.body_type)
2431            }),
2432            Some(
2433                spec.lateral
2434                    .read()
2435                    .0
2436                    .mesh_wing_fl(body.species, body.body_type),
2437            ),
2438            Some(
2439                spec.lateral
2440                    .read()
2441                    .0
2442                    .mesh_wing_fr(body.species, body.body_type),
2443            ),
2444            Some(
2445                spec.lateral
2446                    .read()
2447                    .0
2448                    .mesh_wing_bl(body.species, body.body_type),
2449            ),
2450            Some(
2451                spec.lateral
2452                    .read()
2453                    .0
2454                    .mesh_wing_br(body.species, body.body_type),
2455            ),
2456            Some(
2457                spec.lateral
2458                    .read()
2459                    .0
2460                    .mesh_leg_fl(body.species, body.body_type),
2461            ),
2462            Some(
2463                spec.lateral
2464                    .read()
2465                    .0
2466                    .mesh_leg_fr(body.species, body.body_type),
2467            ),
2468            Some(
2469                spec.lateral
2470                    .read()
2471                    .0
2472                    .mesh_leg_fcl(body.species, body.body_type),
2473            ),
2474            Some(
2475                spec.lateral
2476                    .read()
2477                    .0
2478                    .mesh_leg_fcr(body.species, body.body_type),
2479            ),
2480            Some(
2481                spec.lateral
2482                    .read()
2483                    .0
2484                    .mesh_leg_bcl(body.species, body.body_type),
2485            ),
2486            Some(
2487                spec.lateral
2488                    .read()
2489                    .0
2490                    .mesh_leg_bcr(body.species, body.body_type),
2491            ),
2492            Some(
2493                spec.lateral
2494                    .read()
2495                    .0
2496                    .mesh_leg_bl(body.species, body.body_type),
2497            ),
2498            Some(
2499                spec.lateral
2500                    .read()
2501                    .0
2502                    .mesh_leg_br(body.species, body.body_type),
2503            ),
2504        ]
2505    },
2506);
2507
2508impl ArthropodCentralSpec {
2509    fn mesh_head(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2510        let spec = match self.0.get(&(species, body_type)) {
2511            Some(spec) => spec,
2512            None => {
2513                error!(
2514                    "No head specification exists for the combination of {:?} and {:?}",
2515                    species, body_type
2516                );
2517                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2518            },
2519        };
2520        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
2521
2522        (central, Vec3::from(spec.head.offset))
2523    }
2524
2525    fn mesh_chest(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2526        let spec = match self.0.get(&(species, body_type)) {
2527            Some(spec) => spec,
2528            None => {
2529                error!(
2530                    "No chest specification exists for the combination of {:?} and {:?}",
2531                    species, body_type
2532                );
2533                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2534            },
2535        };
2536        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
2537
2538        (central, Vec3::from(spec.chest.offset))
2539    }
2540}
2541impl ArthropodLateralSpec {
2542    fn mesh_mandible_l(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2543        let spec = match self.0.get(&(species, body_type)) {
2544            Some(spec) => spec,
2545            None => {
2546                error!(
2547                    "No left mandible specification exists for the combination of {:?} and {:?}",
2548                    species, body_type
2549                );
2550                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2551            },
2552        };
2553        let lateral = graceful_load_segment_flipped(
2554            &spec.mandible_l.lateral.0,
2555            true,
2556            spec.mandible_l.model_index,
2557        );
2558
2559        (lateral, Vec3::from(spec.mandible_l.offset))
2560    }
2561
2562    fn mesh_mandible_r(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2563        let spec = match self.0.get(&(species, body_type)) {
2564            Some(spec) => spec,
2565            None => {
2566                error!(
2567                    "No right mandible specification exists for the combination of {:?} and {:?}",
2568                    species, body_type
2569                );
2570                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2571            },
2572        };
2573        let lateral =
2574            graceful_load_segment(&spec.mandible_r.lateral.0, spec.mandible_r.model_index);
2575
2576        (lateral, Vec3::from(spec.mandible_r.offset))
2577    }
2578
2579    fn mesh_wing_fl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2580        let spec = match self.0.get(&(species, body_type)) {
2581            Some(spec) => spec,
2582            None => {
2583                error!(
2584                    "No front left wing specification exists for the combination of {:?} and {:?}",
2585                    species, body_type
2586                );
2587                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2588            },
2589        };
2590        let lateral =
2591            graceful_load_segment_flipped(&spec.wing_fl.lateral.0, true, spec.wing_fl.model_index);
2592
2593        (lateral, Vec3::from(spec.wing_fl.offset))
2594    }
2595
2596    fn mesh_wing_fr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2597        let spec = match self.0.get(&(species, body_type)) {
2598            Some(spec) => spec,
2599            None => {
2600                error!(
2601                    "No front right wing specification exists for the combination of {:?} and {:?}",
2602                    species, body_type
2603                );
2604                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2605            },
2606        };
2607        let lateral = graceful_load_segment(&spec.wing_fr.lateral.0, spec.wing_fr.model_index);
2608
2609        (lateral, Vec3::from(spec.wing_fr.offset))
2610    }
2611
2612    fn mesh_wing_bl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2613        let spec = match self.0.get(&(species, body_type)) {
2614            Some(spec) => spec,
2615            None => {
2616                error!(
2617                    "No back left wing specification exists for the combination of {:?} and {:?}",
2618                    species, body_type
2619                );
2620                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2621            },
2622        };
2623        let lateral =
2624            graceful_load_segment_flipped(&spec.wing_bl.lateral.0, true, spec.wing_bl.model_index);
2625
2626        (lateral, Vec3::from(spec.wing_bl.offset))
2627    }
2628
2629    fn mesh_wing_br(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2630        let spec = match self.0.get(&(species, body_type)) {
2631            Some(spec) => spec,
2632            None => {
2633                error!(
2634                    "No back right wing specification exists for the combination of {:?} and {:?}",
2635                    species, body_type
2636                );
2637                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2638            },
2639        };
2640        let lateral = graceful_load_segment(&spec.wing_br.lateral.0, spec.wing_br.model_index);
2641
2642        (lateral, Vec3::from(spec.wing_br.offset))
2643    }
2644
2645    fn mesh_leg_fl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2646        let spec = match self.0.get(&(species, body_type)) {
2647            Some(spec) => spec,
2648            None => {
2649                error!(
2650                    "No front left leg specification exists for the combination of {:?} and {:?}",
2651                    species, body_type
2652                );
2653                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2654            },
2655        };
2656        let lateral =
2657            graceful_load_segment_flipped(&spec.leg_fl.lateral.0, true, spec.leg_fl.model_index);
2658
2659        (lateral, Vec3::from(spec.leg_fl.offset))
2660    }
2661
2662    fn mesh_leg_fr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2663        let spec = match self.0.get(&(species, body_type)) {
2664            Some(spec) => spec,
2665            None => {
2666                error!(
2667                    "No front right leg specification exists for the combination of {:?} and {:?}",
2668                    species, body_type
2669                );
2670                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2671            },
2672        };
2673        let lateral = graceful_load_segment(&spec.leg_fr.lateral.0, spec.leg_fr.model_index);
2674
2675        (lateral, Vec3::from(spec.leg_fr.offset))
2676    }
2677
2678    fn mesh_leg_fcl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2679        let spec = match self.0.get(&(species, body_type)) {
2680            Some(spec) => spec,
2681            None => {
2682                error!(
2683                    "No front center left leg specification exists for the combination of {:?} \
2684                     and {:?}",
2685                    species, body_type
2686                );
2687                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2688            },
2689        };
2690        let lateral =
2691            graceful_load_segment_flipped(&spec.leg_fcl.lateral.0, true, spec.leg_fcl.model_index);
2692
2693        (lateral, Vec3::from(spec.leg_fcl.offset))
2694    }
2695
2696    fn mesh_leg_fcr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2697        let spec = match self.0.get(&(species, body_type)) {
2698            Some(spec) => spec,
2699            None => {
2700                error!(
2701                    "No front center right leg specification exists for the combination of {:?} \
2702                     and {:?}",
2703                    species, body_type
2704                );
2705                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2706            },
2707        };
2708        let lateral = graceful_load_segment(&spec.leg_fcr.lateral.0, spec.leg_fcr.model_index);
2709
2710        (lateral, Vec3::from(spec.leg_fcr.offset))
2711    }
2712
2713    fn mesh_leg_bcl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2714        let spec = match self.0.get(&(species, body_type)) {
2715            Some(spec) => spec,
2716            None => {
2717                error!(
2718                    "No back center left leg specification exists for the combination of {:?} and \
2719                     {:?}",
2720                    species, body_type
2721                );
2722                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2723            },
2724        };
2725        let lateral =
2726            graceful_load_segment_flipped(&spec.leg_bcl.lateral.0, true, spec.leg_bcl.model_index);
2727
2728        (lateral, Vec3::from(spec.leg_bcl.offset))
2729    }
2730
2731    fn mesh_leg_bcr(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2732        let spec = match self.0.get(&(species, body_type)) {
2733            Some(spec) => spec,
2734            None => {
2735                error!(
2736                    "No back center right leg specification exists for the combination of {:?} \
2737                     and {:?}",
2738                    species, body_type
2739                );
2740                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2741            },
2742        };
2743        let lateral = graceful_load_segment(&spec.leg_bcr.lateral.0, spec.leg_bcr.model_index);
2744
2745        (lateral, Vec3::from(spec.leg_bcr.offset))
2746    }
2747
2748    fn mesh_leg_bl(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2749        let spec = match self.0.get(&(species, body_type)) {
2750            Some(spec) => spec,
2751            None => {
2752                error!(
2753                    "No back left leg specification exists for the combination of {:?} and {:?}",
2754                    species, body_type
2755                );
2756                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2757            },
2758        };
2759        let lateral =
2760            graceful_load_segment_flipped(&spec.leg_bl.lateral.0, true, spec.leg_bl.model_index);
2761
2762        (lateral, Vec3::from(spec.leg_bl.offset))
2763    }
2764
2765    fn mesh_leg_br(&self, species: ASpecies, body_type: ABodyType) -> BoneMeshes {
2766        let spec = match self.0.get(&(species, body_type)) {
2767            Some(spec) => spec,
2768            None => {
2769                error!(
2770                    "No back right leg specification exists for the combination of {:?} and {:?}",
2771                    species, body_type
2772                );
2773                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2774            },
2775        };
2776        let lateral = graceful_load_segment(&spec.leg_br.lateral.0, spec.leg_br.model_index);
2777
2778        (lateral, Vec3::from(spec.leg_br.offset))
2779    }
2780}
2781//////
2782#[derive(Deserialize)]
2783struct CrustaceanCentralSpec(HashMap<(CSpecies, CBodyType), CrustCentralVoxSpec>);
2784impl_concatenate_for_wrapper!(CrustaceanCentralSpec);
2785
2786#[derive(Deserialize, Default)]
2787#[serde(default)]
2788struct CrustCentralVoxSpec {
2789    chest: CrustaceanCentralSubSpec,
2790    tail_f: CrustaceanCentralSubSpec,
2791    tail_b: CrustaceanCentralSubSpec,
2792}
2793
2794#[derive(Deserialize, Default)]
2795struct CrustaceanCentralSubSpec {
2796    offset: [f32; 3], // Should be relative to initial origin
2797    central: VoxSimple,
2798    #[serde(default)]
2799    model_index: u32,
2800}
2801#[derive(Deserialize)]
2802struct CrustaceanLateralSpec(HashMap<(CSpecies, CBodyType), CrustLateralVoxSpec>);
2803impl_concatenate_for_wrapper!(CrustaceanLateralSpec);
2804
2805#[derive(Deserialize, Default)]
2806#[serde(default)]
2807struct CrustLateralVoxSpec {
2808    arm_l: CrustaceanLateralSubSpec,
2809    pincer_l0: CrustaceanLateralSubSpec,
2810    pincer_l1: CrustaceanLateralSubSpec,
2811    arm_r: CrustaceanLateralSubSpec,
2812    pincer_r0: CrustaceanLateralSubSpec,
2813    pincer_r1: CrustaceanLateralSubSpec,
2814    leg_fl: CrustaceanLateralSubSpec,
2815    leg_cl: CrustaceanLateralSubSpec,
2816    leg_bl: CrustaceanLateralSubSpec,
2817    leg_fr: CrustaceanLateralSubSpec,
2818    leg_cr: CrustaceanLateralSubSpec,
2819    leg_br: CrustaceanLateralSubSpec,
2820}
2821#[derive(Deserialize, Default)]
2822struct CrustaceanLateralSubSpec {
2823    offset: [f32; 3], // Should be relative to initial origin
2824    lateral: VoxMirror,
2825    #[serde(default)]
2826    model_index: u32,
2827}
2828make_vox_spec!(
2829    crustacean::Body,
2830    struct CrustaceanSpec {
2831        central: CrustaceanCentralSpec = "voxygen.voxel.crustacean_central_manifest",
2832        lateral: CrustaceanLateralSpec = "voxygen.voxel.crustacean_lateral_manifest",
2833    },
2834    |FigureKey { body, extra, .. }, spec| {
2835        let third_person = extra
2836            .as_ref()
2837            .and_then(|loadout| loadout.third_person.as_ref());
2838
2839        [
2840            third_person.map(|_| {
2841                spec.central
2842                    .read()
2843                    .0
2844                    .mesh_chest(body.species, body.body_type)
2845            }),
2846            Some(
2847                spec.central
2848                    .read()
2849                    .0
2850                    .mesh_tail_f(body.species, body.body_type),
2851            ),
2852            Some(
2853                spec.central
2854                    .read()
2855                    .0
2856                    .mesh_tail_b(body.species, body.body_type),
2857            ),
2858            Some(
2859                spec.lateral
2860                    .read()
2861                    .0
2862                    .mesh_arm_l(body.species, body.body_type),
2863            ),
2864            Some(
2865                spec.lateral
2866                    .read()
2867                    .0
2868                    .mesh_pincer_l0(body.species, body.body_type),
2869            ),
2870            Some(
2871                spec.lateral
2872                    .read()
2873                    .0
2874                    .mesh_pincer_l1(body.species, body.body_type),
2875            ),
2876            Some(
2877                spec.lateral
2878                    .read()
2879                    .0
2880                    .mesh_arm_r(body.species, body.body_type),
2881            ),
2882            Some(
2883                spec.lateral
2884                    .read()
2885                    .0
2886                    .mesh_pincer_r0(body.species, body.body_type),
2887            ),
2888            Some(
2889                spec.lateral
2890                    .read()
2891                    .0
2892                    .mesh_pincer_r1(body.species, body.body_type),
2893            ),
2894            Some(
2895                spec.lateral
2896                    .read()
2897                    .0
2898                    .mesh_leg_fl(body.species, body.body_type),
2899            ),
2900            Some(
2901                spec.lateral
2902                    .read()
2903                    .0
2904                    .mesh_leg_cl(body.species, body.body_type),
2905            ),
2906            Some(
2907                spec.lateral
2908                    .read()
2909                    .0
2910                    .mesh_leg_bl(body.species, body.body_type),
2911            ),
2912            Some(
2913                spec.lateral
2914                    .read()
2915                    .0
2916                    .mesh_leg_fr(body.species, body.body_type),
2917            ),
2918            Some(
2919                spec.lateral
2920                    .read()
2921                    .0
2922                    .mesh_leg_cr(body.species, body.body_type),
2923            ),
2924            Some(
2925                spec.lateral
2926                    .read()
2927                    .0
2928                    .mesh_leg_br(body.species, body.body_type),
2929            ),
2930            None,
2931        ]
2932    },
2933);
2934
2935impl CrustaceanCentralSpec {
2936    fn mesh_chest(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
2937        let spec = match self.0.get(&(species, body_type)) {
2938            Some(spec) => spec,
2939            None => {
2940                error!(
2941                    "No chest specification exists for the combination of {:?} and {:?}",
2942                    species, body_type
2943                );
2944                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2945            },
2946        };
2947        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
2948
2949        (central, Vec3::from(spec.chest.offset))
2950    }
2951
2952    fn mesh_tail_f(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
2953        let spec = match self.0.get(&(species, body_type)) {
2954            Some(spec) => spec,
2955            None => {
2956                error!(
2957                    "No front tail specification exists for the combination of {:?} and {:?}",
2958                    species, body_type
2959                );
2960                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2961            },
2962        };
2963        let central = graceful_load_segment(&spec.tail_f.central.0, spec.tail_f.model_index);
2964
2965        (central, Vec3::from(spec.tail_f.offset))
2966    }
2967
2968    fn mesh_tail_b(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
2969        let spec = match self.0.get(&(species, body_type)) {
2970            Some(spec) => spec,
2971            None => {
2972                error!(
2973                    "No back tail specification exists for the combination of {:?} and {:?}",
2974                    species, body_type
2975                );
2976                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2977            },
2978        };
2979        let central = graceful_load_segment(&spec.tail_b.central.0, spec.tail_b.model_index);
2980
2981        (central, Vec3::from(spec.tail_b.offset))
2982    }
2983}
2984impl CrustaceanLateralSpec {
2985    fn mesh_arm_l(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
2986        let spec = match self.0.get(&(species, body_type)) {
2987            Some(spec) => spec,
2988            None => {
2989                error!(
2990                    "No left arm specification exists for the combination of {:?} and {:?}",
2991                    species, body_type
2992                );
2993                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
2994            },
2995        };
2996        let lateral = graceful_load_segment_flipped(
2997            &spec.arm_l.lateral.0,
2998            spec.arm_l.lateral.1,
2999            spec.arm_l.model_index,
3000        );
3001
3002        (lateral, Vec3::from(spec.arm_l.offset))
3003    }
3004
3005    fn mesh_pincer_l0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3006        let spec = match self.0.get(&(species, body_type)) {
3007            Some(spec) => spec,
3008            None => {
3009                error!(
3010                    "No left major pincer specification exists for the combination of {:?} and \
3011                     {:?}",
3012                    species, body_type
3013                );
3014                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3015            },
3016        };
3017        let lateral = graceful_load_segment_flipped(
3018            &spec.pincer_l0.lateral.0,
3019            spec.pincer_l0.lateral.1,
3020            spec.pincer_l0.model_index,
3021        );
3022
3023        (lateral, Vec3::from(spec.pincer_l0.offset))
3024    }
3025
3026    fn mesh_pincer_l1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3027        let spec = match self.0.get(&(species, body_type)) {
3028            Some(spec) => spec,
3029            None => {
3030                error!(
3031                    "No left minor pincer specification exists for the combination of {:?} and \
3032                     {:?}",
3033                    species, body_type
3034                );
3035                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3036            },
3037        };
3038        let lateral = graceful_load_segment_flipped(
3039            &spec.pincer_l1.lateral.0,
3040            spec.pincer_l0.lateral.1,
3041            spec.pincer_l1.model_index,
3042        );
3043
3044        (lateral, Vec3::from(spec.pincer_l1.offset))
3045    }
3046
3047    fn mesh_arm_r(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3048        let spec = match self.0.get(&(species, body_type)) {
3049            Some(spec) => spec,
3050            None => {
3051                error!(
3052                    "No right arm specification exists for the combination of {:?} and {:?}",
3053                    species, body_type
3054                );
3055                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3056            },
3057        };
3058        let lateral = graceful_load_segment_flipped(
3059            &spec.arm_r.lateral.0,
3060            spec.arm_r.lateral.1,
3061            spec.arm_r.model_index,
3062        );
3063
3064        (lateral, Vec3::from(spec.arm_r.offset))
3065    }
3066
3067    fn mesh_pincer_r0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3068        let spec = match self.0.get(&(species, body_type)) {
3069            Some(spec) => spec,
3070            None => {
3071                error!(
3072                    "No right major pincer specification exists for the combination of {:?} and \
3073                     {:?}",
3074                    species, body_type
3075                );
3076                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3077            },
3078        };
3079        let lateral = graceful_load_segment_flipped(
3080            &spec.pincer_r0.lateral.0,
3081            spec.pincer_r0.lateral.1,
3082            spec.pincer_r0.model_index,
3083        );
3084
3085        (lateral, Vec3::from(spec.pincer_r0.offset))
3086    }
3087
3088    fn mesh_pincer_r1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3089        let spec = match self.0.get(&(species, body_type)) {
3090            Some(spec) => spec,
3091            None => {
3092                error!(
3093                    "No right minor pincer specification exists for the combination of {:?} and \
3094                     {:?}",
3095                    species, body_type
3096                );
3097                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3098            },
3099        };
3100        let lateral = graceful_load_segment_flipped(
3101            &spec.pincer_r1.lateral.0,
3102            spec.pincer_r1.lateral.1,
3103            spec.pincer_r1.model_index,
3104        );
3105
3106        (lateral, Vec3::from(spec.pincer_r1.offset))
3107    }
3108
3109    fn mesh_leg_fl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3110        let spec = match self.0.get(&(species, body_type)) {
3111            Some(spec) => spec,
3112            None => {
3113                error!(
3114                    "No front left leg specification exists for the combination of {:?} and {:?}",
3115                    species, body_type
3116                );
3117                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3118            },
3119        };
3120        let lateral = graceful_load_segment_flipped(
3121            &spec.leg_fl.lateral.0,
3122            spec.leg_fl.lateral.1,
3123            spec.leg_fl.model_index,
3124        );
3125
3126        (lateral, Vec3::from(spec.leg_fl.offset))
3127    }
3128
3129    fn mesh_leg_cl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3130        let spec = match self.0.get(&(species, body_type)) {
3131            Some(spec) => spec,
3132            None => {
3133                error!(
3134                    "No center left leg specification exists for the combination of {:?} and {:?}",
3135                    species, body_type
3136                );
3137                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3138            },
3139        };
3140        let lateral = graceful_load_segment_flipped(
3141            &spec.leg_cl.lateral.0,
3142            spec.leg_cl.lateral.1,
3143            spec.leg_cl.model_index,
3144        );
3145
3146        (lateral, Vec3::from(spec.leg_cl.offset))
3147    }
3148
3149    fn mesh_leg_bl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3150        let spec = match self.0.get(&(species, body_type)) {
3151            Some(spec) => spec,
3152            None => {
3153                error!(
3154                    "No back left leg specification exists for the combination of {:?} and {:?}",
3155                    species, body_type
3156                );
3157                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3158            },
3159        };
3160        let lateral = graceful_load_segment_flipped(
3161            &spec.leg_bl.lateral.0,
3162            spec.leg_bl.lateral.1,
3163            spec.leg_bl.model_index,
3164        );
3165
3166        (lateral, Vec3::from(spec.leg_bl.offset))
3167    }
3168
3169    fn mesh_leg_fr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3170        let spec = match self.0.get(&(species, body_type)) {
3171            Some(spec) => spec,
3172            None => {
3173                error!(
3174                    "No front right leg specification exists for the combination of {:?} and {:?}",
3175                    species, body_type
3176                );
3177                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3178            },
3179        };
3180        let lateral = graceful_load_segment_flipped(
3181            &spec.leg_fr.lateral.0,
3182            spec.leg_fr.lateral.1,
3183            spec.leg_fr.model_index,
3184        );
3185
3186        (lateral, Vec3::from(spec.leg_fr.offset))
3187    }
3188
3189    fn mesh_leg_cr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3190        let spec = match self.0.get(&(species, body_type)) {
3191            Some(spec) => spec,
3192            None => {
3193                error!(
3194                    "No center right leg specification exists for the combination of {:?} and {:?}",
3195                    species, body_type
3196                );
3197                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3198            },
3199        };
3200        let lateral = graceful_load_segment_flipped(
3201            &spec.leg_cr.lateral.0,
3202            spec.leg_cr.lateral.1,
3203            spec.leg_cr.model_index,
3204        );
3205
3206        (lateral, Vec3::from(spec.leg_cr.offset))
3207    }
3208
3209    fn mesh_leg_br(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
3210        let spec = match self.0.get(&(species, body_type)) {
3211            Some(spec) => spec,
3212            None => {
3213                error!(
3214                    "No back right leg specification exists for the combination of {:?} and {:?}",
3215                    species, body_type
3216                );
3217                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3218            },
3219        };
3220        let lateral = graceful_load_segment_flipped(
3221            &spec.leg_br.lateral.0,
3222            spec.leg_br.lateral.1,
3223            spec.leg_br.model_index,
3224        );
3225
3226        (lateral, Vec3::from(spec.leg_br.offset))
3227    }
3228}
3229
3230#[derive(Deserialize)]
3231struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>);
3232impl_concatenate_for_wrapper!(FishMediumCentralSpec);
3233
3234#[derive(Deserialize, Default)]
3235#[serde(default)]
3236struct SidedFMCentralVoxSpec {
3237    head: FishMediumCentralSubSpec,
3238    jaw: FishMediumCentralSubSpec,
3239    chest_front: FishMediumCentralSubSpec,
3240    chest_back: FishMediumCentralSubSpec,
3241    tail: FishMediumCentralSubSpec,
3242}
3243
3244#[derive(Deserialize, Default)]
3245struct FishMediumCentralSubSpec {
3246    offset: [f32; 3], // Should be relative to initial origin
3247    central: VoxSimple,
3248    #[serde(default)]
3249    model_index: u32,
3250}
3251
3252#[derive(Deserialize)]
3253struct FishMediumLateralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMLateralVoxSpec>);
3254impl_concatenate_for_wrapper!(FishMediumLateralSpec);
3255
3256#[derive(Deserialize, Default)]
3257#[serde(default)]
3258struct SidedFMLateralVoxSpec {
3259    fin_l: FishMediumLateralSubSpec,
3260    fin_r: FishMediumLateralSubSpec,
3261}
3262#[derive(Deserialize, Default)]
3263struct FishMediumLateralSubSpec {
3264    offset: [f32; 3], // Should be relative to initial origin
3265    lateral: VoxSimple,
3266    #[serde(default)]
3267    model_index: u32,
3268}
3269
3270make_vox_spec!(
3271    fish_medium::Body,
3272    struct FishMediumSpec {
3273        central: FishMediumCentralSpec = "voxygen.voxel.fish_medium_central_manifest",
3274        lateral: FishMediumLateralSpec = "voxygen.voxel.fish_medium_lateral_manifest",
3275    },
3276    |FigureKey { body, extra, .. }, spec| {
3277        let third_person = extra
3278            .as_ref()
3279            .and_then(|loadout| loadout.third_person.as_ref());
3280
3281        [
3282            third_person.map(|_| {
3283                spec.central
3284                    .read()
3285                    .0
3286                    .mesh_head(body.species, body.body_type)
3287            }),
3288            Some(spec.central.read().0.mesh_jaw(body.species, body.body_type)),
3289            Some(
3290                spec.central
3291                    .read()
3292                    .0
3293                    .mesh_chest_front(body.species, body.body_type),
3294            ),
3295            Some(
3296                spec.central
3297                    .read()
3298                    .0
3299                    .mesh_chest_back(body.species, body.body_type),
3300            ),
3301            Some(
3302                spec.central
3303                    .read()
3304                    .0
3305                    .mesh_tail(body.species, body.body_type),
3306            ),
3307            Some(
3308                spec.lateral
3309                    .read()
3310                    .0
3311                    .mesh_fin_l(body.species, body.body_type),
3312            ),
3313            Some(
3314                spec.lateral
3315                    .read()
3316                    .0
3317                    .mesh_fin_r(body.species, body.body_type),
3318            ),
3319            None,
3320            None,
3321            None,
3322            None,
3323            None,
3324            None,
3325            None,
3326            None,
3327            None,
3328        ]
3329    },
3330);
3331
3332impl FishMediumCentralSpec {
3333    fn mesh_head(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3334        let spec = match self.0.get(&(species, body_type)) {
3335            Some(spec) => spec,
3336            None => {
3337                error!(
3338                    "No head specification exists for the combination of {:?} and {:?}",
3339                    species, body_type
3340                );
3341                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3342            },
3343        };
3344        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
3345
3346        (central, Vec3::from(spec.head.offset))
3347    }
3348
3349    fn mesh_jaw(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3350        let spec = match self.0.get(&(species, body_type)) {
3351            Some(spec) => spec,
3352            None => {
3353                error!(
3354                    "No jaw specification exists for the combination of {:?} and {:?}",
3355                    species, body_type
3356                );
3357                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3358            },
3359        };
3360        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
3361
3362        (central, Vec3::from(spec.jaw.offset))
3363    }
3364
3365    fn mesh_chest_front(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3366        let spec = match self.0.get(&(species, body_type)) {
3367            Some(spec) => spec,
3368            None => {
3369                error!(
3370                    "No front chest specification exists for the combination of {:?} and {:?}",
3371                    species, body_type
3372                );
3373                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3374            },
3375        };
3376        let central =
3377            graceful_load_segment(&spec.chest_front.central.0, spec.chest_front.model_index);
3378
3379        (central, Vec3::from(spec.chest_front.offset))
3380    }
3381
3382    fn mesh_chest_back(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3383        let spec = match self.0.get(&(species, body_type)) {
3384            Some(spec) => spec,
3385            None => {
3386                error!(
3387                    "No back chest specification exists for the combination of {:?} and {:?}",
3388                    species, body_type
3389                );
3390                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3391            },
3392        };
3393        let central =
3394            graceful_load_segment(&spec.chest_back.central.0, spec.chest_back.model_index);
3395
3396        (central, Vec3::from(spec.chest_back.offset))
3397    }
3398
3399    fn mesh_tail(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3400        let spec = match self.0.get(&(species, body_type)) {
3401            Some(spec) => spec,
3402            None => {
3403                error!(
3404                    "No tail specification exists for the combination of {:?} and {:?}",
3405                    species, body_type
3406                );
3407                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3408            },
3409        };
3410        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
3411
3412        (central, Vec3::from(spec.tail.offset))
3413    }
3414}
3415
3416impl FishMediumLateralSpec {
3417    fn mesh_fin_l(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3418        let spec = match self.0.get(&(species, body_type)) {
3419            Some(spec) => spec,
3420            None => {
3421                error!(
3422                    "No fin specification exists for the combination of {:?} and {:?}",
3423                    species, body_type
3424                );
3425                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3426            },
3427        };
3428        let lateral =
3429            graceful_load_segment_flipped(&spec.fin_l.lateral.0, true, spec.fin_l.model_index);
3430
3431        (lateral, Vec3::from(spec.fin_l.offset))
3432    }
3433
3434    fn mesh_fin_r(&self, species: FMSpecies, body_type: FMBodyType) -> BoneMeshes {
3435        let spec = match self.0.get(&(species, body_type)) {
3436            Some(spec) => spec,
3437            None => {
3438                error!(
3439                    "No fin specification exists for the combination of {:?} and {:?}",
3440                    species, body_type
3441                );
3442                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3443            },
3444        };
3445        let lateral = graceful_load_segment(&spec.fin_r.lateral.0, spec.fin_r.model_index);
3446
3447        (lateral, Vec3::from(spec.fin_r.offset))
3448    }
3449}
3450
3451//////
3452#[derive(Deserialize)]
3453struct FishSmallCentralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSCentralVoxSpec>);
3454impl_concatenate_for_wrapper!(FishSmallCentralSpec);
3455
3456#[derive(Deserialize, Default)]
3457#[serde(default)]
3458struct SidedFSCentralVoxSpec {
3459    chest: FishSmallCentralSubSpec,
3460    tail: FishSmallCentralSubSpec,
3461}
3462
3463#[derive(Deserialize, Default)]
3464struct FishSmallCentralSubSpec {
3465    offset: [f32; 3], // Should be relative to initial origin
3466    central: VoxSimple,
3467    #[serde(default)]
3468    model_index: u32,
3469}
3470
3471#[derive(Deserialize)]
3472struct FishSmallLateralSpec(HashMap<(FSSpecies, FSBodyType), SidedFSLateralVoxSpec>);
3473impl_concatenate_for_wrapper!(FishSmallLateralSpec);
3474
3475#[derive(Deserialize, Default)]
3476#[serde(default)]
3477struct SidedFSLateralVoxSpec {
3478    fin_l: FishSmallLateralSubSpec,
3479    fin_r: FishSmallLateralSubSpec,
3480}
3481
3482#[derive(Deserialize, Default)]
3483struct FishSmallLateralSubSpec {
3484    offset: [f32; 3], // Should be relative to initial origin
3485    lateral: VoxSimple,
3486    #[serde(default)]
3487    model_index: u32,
3488}
3489
3490make_vox_spec!(
3491    fish_small::Body,
3492    struct FishSmallSpec {
3493        central: FishSmallCentralSpec = "voxygen.voxel.fish_small_central_manifest",
3494        lateral: FishSmallLateralSpec = "voxygen.voxel.fish_small_lateral_manifest",
3495    },
3496    |FigureKey { body, extra, .. }, spec| {
3497        let third_person = extra
3498            .as_ref()
3499            .and_then(|loadout| loadout.third_person.as_ref());
3500
3501        [
3502            third_person.map(|_| {
3503                spec.central
3504                    .read()
3505                    .0
3506                    .mesh_chest(body.species, body.body_type)
3507            }),
3508            Some(
3509                spec.central
3510                    .read()
3511                    .0
3512                    .mesh_tail(body.species, body.body_type),
3513            ),
3514            Some(
3515                spec.lateral
3516                    .read()
3517                    .0
3518                    .mesh_fin_l(body.species, body.body_type),
3519            ),
3520            Some(
3521                spec.lateral
3522                    .read()
3523                    .0
3524                    .mesh_fin_r(body.species, body.body_type),
3525            ),
3526            None,
3527            None,
3528            None,
3529            None,
3530            None,
3531            None,
3532            None,
3533            None,
3534            None,
3535            None,
3536            None,
3537            None,
3538        ]
3539    },
3540);
3541
3542impl FishSmallCentralSpec {
3543    fn mesh_chest(&self, species: FSSpecies, body_type: FSBodyType) -> BoneMeshes {
3544        let spec = match self.0.get(&(species, body_type)) {
3545            Some(spec) => spec,
3546            None => {
3547                error!(
3548                    "No chest specification exists for the combination of {:?} and {:?}",
3549                    species, body_type
3550                );
3551                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3552            },
3553        };
3554        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
3555
3556        (central, Vec3::from(spec.chest.offset))
3557    }
3558
3559    fn mesh_tail(&self, species: FSSpecies, body_type: FSBodyType) -> BoneMeshes {
3560        let spec = match self.0.get(&(species, body_type)) {
3561            Some(spec) => spec,
3562            None => {
3563                error!(
3564                    "No tail specification exists for the combination of {:?} and {:?}",
3565                    species, body_type
3566                );
3567                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3568            },
3569        };
3570        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
3571
3572        (central, Vec3::from(spec.tail.offset))
3573    }
3574}
3575
3576impl FishSmallLateralSpec {
3577    fn mesh_fin_l(&self, species: FSSpecies, body_type: FSBodyType) -> BoneMeshes {
3578        let spec = match self.0.get(&(species, body_type)) {
3579            Some(spec) => spec,
3580            None => {
3581                error!(
3582                    "No fin specification exists for the combination of {:?} and {:?}",
3583                    species, body_type
3584                );
3585                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3586            },
3587        };
3588        let lateral =
3589            graceful_load_segment_flipped(&spec.fin_l.lateral.0, true, spec.fin_l.model_index);
3590
3591        (lateral, Vec3::from(spec.fin_l.offset))
3592    }
3593
3594    fn mesh_fin_r(&self, species: FSSpecies, body_type: FSBodyType) -> BoneMeshes {
3595        let spec = match self.0.get(&(species, body_type)) {
3596            Some(spec) => spec,
3597            None => {
3598                error!(
3599                    "No fin specification exists for the combination of {:?} and {:?}",
3600                    species, body_type
3601                );
3602                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
3603            },
3604        };
3605        let lateral = graceful_load_segment(&spec.fin_r.lateral.0, spec.fin_r.model_index);
3606
3607        (lateral, Vec3::from(spec.fin_r.offset))
3608    }
3609}
3610
3611//////
3612
3613#[derive(Deserialize)]
3614struct BipedSmallWeaponSpec(HashMap<ToolKey, ArmorVoxSpec>);
3615impl_concatenate_for_wrapper!(BipedSmallWeaponSpec);
3616#[derive(Deserialize)]
3617struct BipedSmallArmorHeadSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
3618impl_concatenate_for_wrapper!(BipedSmallArmorHeadSpec);
3619#[derive(Deserialize)]
3620struct BipedSmallArmorHandSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
3621impl_concatenate_for_wrapper!(BipedSmallArmorHandSpec);
3622#[derive(Deserialize)]
3623struct BipedSmallArmorFootSpec(ArmorVoxSpecMap<String, SidedArmorVoxSpec>);
3624impl_concatenate_for_wrapper!(BipedSmallArmorFootSpec);
3625#[derive(Deserialize)]
3626struct BipedSmallArmorChestSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
3627impl_concatenate_for_wrapper!(BipedSmallArmorChestSpec);
3628#[derive(Deserialize)]
3629struct BipedSmallArmorPantsSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
3630impl_concatenate_for_wrapper!(BipedSmallArmorPantsSpec);
3631#[derive(Deserialize)]
3632struct BipedSmallArmorTailSpec(ArmorVoxSpecMap<String, ArmorVoxSpec>);
3633impl_concatenate_for_wrapper!(BipedSmallArmorTailSpec);
3634make_vox_spec!(
3635    biped_small::Body,
3636    struct BipedSmallSpec {
3637        armor_foot: BipedSmallArmorFootSpec = "voxygen.voxel.biped_small_armor_foot_manifest",
3638        weapon: BipedSmallWeaponSpec = "voxygen.voxel.biped_weapon_manifest",
3639        armor_hand: BipedSmallArmorHandSpec = "voxygen.voxel.biped_small_armor_hand_manifest",
3640        armor_chest: BipedSmallArmorChestSpec = "voxygen.voxel.biped_small_armor_chest_manifest",
3641        armor_pants: BipedSmallArmorPantsSpec = "voxygen.voxel.biped_small_armor_pants_manifest",
3642        armor_head: BipedSmallArmorHeadSpec = "voxygen.voxel.biped_small_armor_head_manifest",
3643        armor_tail: BipedSmallArmorTailSpec = "voxygen.voxel.biped_small_armor_tail_manifest",
3644
3645    },
3646    |FigureKey {
3647         body: _,
3648         item_key: _,
3649         extra,
3650     },
3651     spec| {
3652        const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
3653            third_person: None,
3654            tool: None,
3655            lantern: None,
3656            glider: None,
3657            hand: None,
3658            foot: None,
3659            head: None,
3660        };
3661
3662        // TODO: This is bad code, maybe this method should return Option<_>
3663        let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT);
3664        let third_person = loadout.third_person.as_ref();
3665        let tool = loadout.tool.as_ref();
3666        let hand = loadout.hand.as_deref();
3667        let foot = loadout.foot.as_deref();
3668
3669        [
3670            third_person.map(|loadout| spec.armor_head.read().0.mesh_head(loadout.head.as_deref())),
3671            third_person.map(|loadout| {
3672                spec.armor_chest
3673                    .read()
3674                    .0
3675                    .mesh_chest(loadout.chest.as_deref())
3676            }),
3677            third_person.map(|loadout| {
3678                spec.armor_pants
3679                    .read()
3680                    .0
3681                    .mesh_pants(loadout.pants.as_deref())
3682            }),
3683            third_person.map(|loadout| spec.armor_tail.read().0.mesh_tail(loadout.belt.as_deref())),
3684            tool.and_then(|tool| tool.active.as_ref())
3685                .map(|tool| spec.weapon.read().0.mesh_main(tool, false)),
3686            Some(spec.armor_hand.read().0.mesh_left_hand(hand)),
3687            Some(spec.armor_hand.read().0.mesh_right_hand(hand)),
3688            Some(spec.armor_foot.read().0.mesh_left_foot(foot)),
3689            Some(spec.armor_foot.read().0.mesh_right_foot(foot)),
3690            None,
3691            None,
3692            None,
3693            None,
3694            None,
3695            None,
3696            None,
3697        ]
3698    },
3699);
3700
3701impl BipedSmallArmorHeadSpec {
3702    fn mesh_head(&self, head: Option<&str>) -> BoneMeshes {
3703        let spec = if let Some(head) = head {
3704            match self.0.map.get(head) {
3705                Some(spec) => spec,
3706                None => {
3707                    error!(?head, "No head specification exists");
3708                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3709                },
3710            }
3711        } else {
3712            &self.0.default
3713        };
3714
3715        let head_segment = graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2);
3716
3717        let offset = Vec3::new(spec.vox_spec.1[0], spec.vox_spec.1[1], spec.vox_spec.1[2]);
3718
3719        (head_segment, offset)
3720    }
3721}
3722impl BipedSmallArmorChestSpec {
3723    fn mesh_chest(&self, chest: Option<&str>) -> BoneMeshes {
3724        let spec = if let Some(chest) = chest {
3725            match self.0.map.get(chest) {
3726                Some(spec) => spec,
3727                None => {
3728                    error!(?chest, "No chest specification exists");
3729                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3730                },
3731            }
3732        } else {
3733            &self.0.default
3734        };
3735
3736        let chest_segment = graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2);
3737
3738        let offset = Vec3::new(spec.vox_spec.1[0], spec.vox_spec.1[1], spec.vox_spec.1[2]);
3739
3740        (chest_segment, offset)
3741    }
3742}
3743impl BipedSmallArmorTailSpec {
3744    fn mesh_tail(&self, tail: Option<&str>) -> BoneMeshes {
3745        let spec = if let Some(tail) = tail {
3746            match self.0.map.get(tail) {
3747                Some(spec) => spec,
3748                None => {
3749                    error!(?tail, "No tail specification exists");
3750                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3751                },
3752            }
3753        } else {
3754            &self.0.default
3755        };
3756
3757        let tail_segment = graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2);
3758
3759        let offset = Vec3::new(spec.vox_spec.1[0], spec.vox_spec.1[1], spec.vox_spec.1[2]);
3760
3761        (tail_segment, offset)
3762    }
3763}
3764impl BipedSmallArmorPantsSpec {
3765    fn mesh_pants(&self, pants: Option<&str>) -> BoneMeshes {
3766        let spec = if let Some(pants) = pants {
3767            match self.0.map.get(pants) {
3768                Some(spec) => spec,
3769                None => {
3770                    error!(?pants, "No pants specification exists");
3771                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3772                },
3773            }
3774        } else {
3775            &self.0.default
3776        };
3777
3778        let pants_segment = graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2);
3779
3780        let offset = Vec3::new(spec.vox_spec.1[0], spec.vox_spec.1[1], spec.vox_spec.1[2]);
3781
3782        (pants_segment, offset)
3783    }
3784}
3785impl BipedSmallArmorHandSpec {
3786    fn mesh_hand(&self, hand: Option<&str>, flipped: bool) -> BoneMeshes {
3787        let spec = if let Some(hand) = hand {
3788            match self.0.map.get(hand) {
3789                Some(spec) => spec,
3790                None => {
3791                    error!(?hand, "No hand specification exists");
3792                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3793                },
3794            }
3795        } else {
3796            &self.0.default
3797        };
3798
3799        let hand_segment = if flipped {
3800            graceful_load_segment_flipped(&spec.left.vox_spec.0, true, spec.left.vox_spec.2)
3801        } else {
3802            graceful_load_segment(&spec.right.vox_spec.0, spec.right.vox_spec.2)
3803        };
3804        let offset = if flipped {
3805            spec.left.vox_spec.1
3806        } else {
3807            spec.right.vox_spec.1
3808        };
3809
3810        (hand_segment, Vec3::from(offset))
3811    }
3812
3813    fn mesh_left_hand(&self, hand: Option<&str>) -> BoneMeshes { self.mesh_hand(hand, true) }
3814
3815    fn mesh_right_hand(&self, hand: Option<&str>) -> BoneMeshes { self.mesh_hand(hand, false) }
3816}
3817impl BipedSmallArmorFootSpec {
3818    fn mesh_foot(&self, foot: Option<&str>, flipped: bool) -> BoneMeshes {
3819        let spec = if let Some(foot) = foot {
3820            match self.0.map.get(foot) {
3821                Some(spec) => spec,
3822                None => {
3823                    error!(?foot, "No foot specification exists");
3824                    return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3825                },
3826            }
3827        } else {
3828            &self.0.default
3829        };
3830
3831        let foot_segment = if flipped {
3832            graceful_load_segment_flipped(&spec.left.vox_spec.0, true, spec.left.vox_spec.2)
3833        } else {
3834            graceful_load_segment(&spec.right.vox_spec.0, spec.right.vox_spec.2)
3835        };
3836        let offset = if flipped {
3837            spec.left.vox_spec.1
3838        } else {
3839            spec.right.vox_spec.1
3840        };
3841
3842        (foot_segment, Vec3::from(offset))
3843    }
3844
3845    fn mesh_left_foot(&self, foot: Option<&str>) -> BoneMeshes { self.mesh_foot(foot, true) }
3846
3847    fn mesh_right_foot(&self, foot: Option<&str>) -> BoneMeshes { self.mesh_foot(foot, false) }
3848}
3849
3850impl BipedSmallWeaponSpec {
3851    fn mesh_main(&self, tool: &ToolKey, flipped: bool) -> BoneMeshes {
3852        let spec = match self.0.get(tool) {
3853            Some(spec) => spec,
3854            None => {
3855                error!(?tool, "No tool/weapon specification exists");
3856                return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
3857            },
3858        };
3859
3860        let tool_kind_segment = if flipped {
3861            graceful_load_segment_flipped(&spec.vox_spec.0, true, spec.vox_spec.2)
3862        } else {
3863            graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2)
3864        };
3865
3866        let offset = Vec3::new(
3867            if flipped {
3868                0.0 - spec.vox_spec.1[0] - (tool_kind_segment.sz.x as f32)
3869            } else {
3870                spec.vox_spec.1[0]
3871            },
3872            spec.vox_spec.1[1],
3873            spec.vox_spec.1[2],
3874        );
3875
3876        (tool_kind_segment, offset)
3877    }
3878}
3879
3880//////
3881#[derive(Deserialize)]
3882struct DragonCentralSpec(HashMap<(DSpecies, DBodyType), SidedDCentralVoxSpec>);
3883impl_concatenate_for_wrapper!(DragonCentralSpec);
3884
3885#[derive(Deserialize, Default)]
3886#[serde(default)]
3887struct SidedDCentralVoxSpec {
3888    upper: DragonCentralSubSpec,
3889    lower: DragonCentralSubSpec,
3890    jaw: DragonCentralSubSpec,
3891    chest_front: DragonCentralSubSpec,
3892    chest_rear: DragonCentralSubSpec,
3893    tail_front: DragonCentralSubSpec,
3894    tail_rear: DragonCentralSubSpec,
3895}
3896#[derive(Deserialize, Default)]
3897struct DragonCentralSubSpec {
3898    offset: [f32; 3], // Should be relative to initial origin
3899    central: VoxSimple,
3900    #[serde(default)]
3901    model_index: u32,
3902}
3903
3904#[derive(Deserialize)]
3905struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>);
3906impl_concatenate_for_wrapper!(DragonLateralSpec);
3907
3908#[derive(Deserialize, Default)]
3909#[serde(default)]
3910struct SidedDLateralVoxSpec {
3911    wing_in_l: DragonLateralSubSpec,
3912    wing_in_r: DragonLateralSubSpec,
3913    wing_out_l: DragonLateralSubSpec,
3914    wing_out_r: DragonLateralSubSpec,
3915    foot_fl: DragonLateralSubSpec,
3916    foot_fr: DragonLateralSubSpec,
3917    foot_bl: DragonLateralSubSpec,
3918    foot_br: DragonLateralSubSpec,
3919}
3920#[derive(Deserialize, Default)]
3921struct DragonLateralSubSpec {
3922    offset: [f32; 3], // Should be relative to initial origin
3923    lateral: VoxSimple,
3924    #[serde(default)]
3925    model_index: u32,
3926}
3927
3928make_vox_spec!(
3929    dragon::Body,
3930    struct DragonSpec {
3931        central: DragonCentralSpec = "voxygen.voxel.dragon_central_manifest",
3932        lateral: DragonLateralSpec = "voxygen.voxel.dragon_lateral_manifest",
3933    },
3934    |FigureKey { body, extra, .. }, spec| {
3935        let third_person = extra
3936            .as_ref()
3937            .and_then(|loadout| loadout.third_person.as_ref());
3938
3939        [
3940            third_person.map(|_| {
3941                spec.central
3942                    .read()
3943                    .0
3944                    .mesh_head_upper(body.species, body.body_type)
3945            }),
3946            Some(
3947                spec.central
3948                    .read()
3949                    .0
3950                    .mesh_head_lower(body.species, body.body_type),
3951            ),
3952            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
3953            Some(
3954                spec.central
3955                    .read()
3956                    .0
3957                    .mesh_chest_front(body.species, body.body_type),
3958            ),
3959            Some(
3960                spec.central
3961                    .read()
3962                    .0
3963                    .mesh_chest_rear(body.species, body.body_type),
3964            ),
3965            Some(
3966                spec.central
3967                    .read()
3968                    .0
3969                    .mesh_tail_front(body.species, body.body_type),
3970            ),
3971            Some(
3972                spec.central
3973                    .read()
3974                    .0
3975                    .mesh_tail_rear(body.species, body.body_type),
3976            ),
3977            Some(
3978                spec.lateral
3979                    .read()
3980                    .0
3981                    .mesh_wing_in_l(body.species, body.body_type),
3982            ),
3983            Some(
3984                spec.lateral
3985                    .read()
3986                    .0
3987                    .mesh_wing_in_r(body.species, body.body_type),
3988            ),
3989            Some(
3990                spec.lateral
3991                    .read()
3992                    .0
3993                    .mesh_wing_out_l(body.species, body.body_type),
3994            ),
3995            Some(
3996                spec.lateral
3997                    .read()
3998                    .0
3999                    .mesh_wing_out_r(body.species, body.body_type),
4000            ),
4001            Some(
4002                spec.lateral
4003                    .read()
4004                    .0
4005                    .mesh_foot_fl(body.species, body.body_type),
4006            ),
4007            Some(
4008                spec.lateral
4009                    .read()
4010                    .0
4011                    .mesh_foot_fr(body.species, body.body_type),
4012            ),
4013            Some(
4014                spec.lateral
4015                    .read()
4016                    .0
4017                    .mesh_foot_bl(body.species, body.body_type),
4018            ),
4019            Some(
4020                spec.lateral
4021                    .read()
4022                    .0
4023                    .mesh_foot_br(body.species, body.body_type),
4024            ),
4025            None,
4026        ]
4027    },
4028);
4029
4030impl DragonCentralSpec {
4031    fn mesh_head_upper(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4032        let spec = match self.0.get(&(species, body_type)) {
4033            Some(spec) => spec,
4034            None => {
4035                error!(
4036                    "No upper head specification exists for the combination of {:?} and {:?}",
4037                    species, body_type
4038                );
4039                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4040            },
4041        };
4042        let central = graceful_load_segment(&spec.upper.central.0, spec.upper.model_index);
4043
4044        (central, Vec3::from(spec.upper.offset))
4045    }
4046
4047    fn mesh_head_lower(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4048        let spec = match self.0.get(&(species, body_type)) {
4049            Some(spec) => spec,
4050            None => {
4051                error!(
4052                    "No lower head specification exists for the combination of {:?} and {:?}",
4053                    species, body_type
4054                );
4055                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4056            },
4057        };
4058        let central = graceful_load_segment(&spec.lower.central.0, spec.lower.model_index);
4059
4060        (central, Vec3::from(spec.lower.offset))
4061    }
4062
4063    fn mesh_jaw(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4064        let spec = match self.0.get(&(species, body_type)) {
4065            Some(spec) => spec,
4066            None => {
4067                error!(
4068                    "No jaw specification exists for the combination of {:?} and {:?}",
4069                    species, body_type
4070                );
4071                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4072            },
4073        };
4074        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
4075
4076        (central, Vec3::from(spec.jaw.offset))
4077    }
4078
4079    fn mesh_chest_front(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4080        let spec = match self.0.get(&(species, body_type)) {
4081            Some(spec) => spec,
4082            None => {
4083                error!(
4084                    "No chest front specification exists for the combination of {:?} and {:?}",
4085                    species, body_type
4086                );
4087                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4088            },
4089        };
4090        let central =
4091            graceful_load_segment(&spec.chest_front.central.0, spec.chest_front.model_index);
4092
4093        (central, Vec3::from(spec.chest_front.offset))
4094    }
4095
4096    fn mesh_chest_rear(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4097        let spec = match self.0.get(&(species, body_type)) {
4098            Some(spec) => spec,
4099            None => {
4100                error!(
4101                    "No chest rear specification exists for the combination of {:?} and {:?}",
4102                    species, body_type
4103                );
4104                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4105            },
4106        };
4107        let central =
4108            graceful_load_segment(&spec.chest_rear.central.0, spec.chest_rear.model_index);
4109
4110        (central, Vec3::from(spec.chest_rear.offset))
4111    }
4112
4113    fn mesh_tail_front(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4114        let spec = match self.0.get(&(species, body_type)) {
4115            Some(spec) => spec,
4116            None => {
4117                error!(
4118                    "No tail front specification exists for the combination of {:?} and {:?}",
4119                    species, body_type
4120                );
4121                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4122            },
4123        };
4124        let central =
4125            graceful_load_segment(&spec.tail_front.central.0, spec.tail_front.model_index);
4126
4127        (central, Vec3::from(spec.tail_front.offset))
4128    }
4129
4130    fn mesh_tail_rear(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4131        let spec = match self.0.get(&(species, body_type)) {
4132            Some(spec) => spec,
4133            None => {
4134                error!(
4135                    "No tail rear specification exists for the combination of {:?} and {:?}",
4136                    species, body_type
4137                );
4138                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4139            },
4140        };
4141        let central = graceful_load_segment(&spec.tail_rear.central.0, spec.tail_rear.model_index);
4142
4143        (central, Vec3::from(spec.tail_rear.offset))
4144    }
4145}
4146impl DragonLateralSpec {
4147    fn mesh_wing_in_l(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4148        let spec = match self.0.get(&(species, body_type)) {
4149            Some(spec) => spec,
4150            None => {
4151                error!(
4152                    "No wing specification exists for the combination of {:?} and {:?}",
4153                    species, body_type
4154                );
4155                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4156            },
4157        };
4158        let lateral = graceful_load_segment(&spec.wing_in_l.lateral.0, spec.wing_in_l.model_index);
4159
4160        (lateral, Vec3::from(spec.wing_in_l.offset))
4161    }
4162
4163    fn mesh_wing_in_r(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4164        let spec = match self.0.get(&(species, body_type)) {
4165            Some(spec) => spec,
4166            None => {
4167                error!(
4168                    "No wing specification exists for the combination of {:?} and {:?}",
4169                    species, body_type
4170                );
4171                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4172            },
4173        };
4174        let lateral = graceful_load_segment(&spec.wing_in_r.lateral.0, spec.wing_in_r.model_index);
4175
4176        (lateral, Vec3::from(spec.wing_in_r.offset))
4177    }
4178
4179    fn mesh_wing_out_l(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4180        let spec = match self.0.get(&(species, body_type)) {
4181            Some(spec) => spec,
4182            None => {
4183                error!(
4184                    "No wing specification exists for the combination of {:?} and {:?}",
4185                    species, body_type
4186                );
4187                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4188            },
4189        };
4190        let lateral =
4191            graceful_load_segment(&spec.wing_out_l.lateral.0, spec.wing_out_l.model_index);
4192
4193        (lateral, Vec3::from(spec.wing_out_l.offset))
4194    }
4195
4196    fn mesh_wing_out_r(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4197        let spec = match self.0.get(&(species, body_type)) {
4198            Some(spec) => spec,
4199            None => {
4200                error!(
4201                    "No wing specification exists for the combination of {:?} and {:?}",
4202                    species, body_type
4203                );
4204                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4205            },
4206        };
4207        let lateral =
4208            graceful_load_segment(&spec.wing_out_r.lateral.0, spec.wing_out_r.model_index);
4209
4210        (lateral, Vec3::from(spec.wing_out_r.offset))
4211    }
4212
4213    fn mesh_foot_fl(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4214        let spec = match self.0.get(&(species, body_type)) {
4215            Some(spec) => spec,
4216            None => {
4217                error!(
4218                    "No foot specification exists for the combination of {:?} and {:?}",
4219                    species, body_type
4220                );
4221                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4222            },
4223        };
4224        let lateral = graceful_load_segment(&spec.foot_fl.lateral.0, spec.foot_fl.model_index);
4225
4226        (lateral, Vec3::from(spec.foot_fl.offset))
4227    }
4228
4229    fn mesh_foot_fr(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4230        let spec = match self.0.get(&(species, body_type)) {
4231            Some(spec) => spec,
4232            None => {
4233                error!(
4234                    "No foot specification exists for the combination of {:?} and {:?}",
4235                    species, body_type
4236                );
4237                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4238            },
4239        };
4240        let lateral = graceful_load_segment(&spec.foot_fr.lateral.0, spec.foot_fr.model_index);
4241
4242        (lateral, Vec3::from(spec.foot_fr.offset))
4243    }
4244
4245    fn mesh_foot_bl(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4246        let spec = match self.0.get(&(species, body_type)) {
4247            Some(spec) => spec,
4248            None => {
4249                error!(
4250                    "No foot specification exists for the combination of {:?} and {:?}",
4251                    species, body_type
4252                );
4253                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4254            },
4255        };
4256        let lateral = graceful_load_segment(&spec.foot_bl.lateral.0, spec.foot_bl.model_index);
4257
4258        (lateral, Vec3::from(spec.foot_bl.offset))
4259    }
4260
4261    fn mesh_foot_br(&self, species: DSpecies, body_type: DBodyType) -> BoneMeshes {
4262        let spec = match self.0.get(&(species, body_type)) {
4263            Some(spec) => spec,
4264            None => {
4265                error!(
4266                    "No foot specification exists for the combination of {:?} and {:?}",
4267                    species, body_type
4268                );
4269                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4270            },
4271        };
4272        let lateral = graceful_load_segment(&spec.foot_br.lateral.0, spec.foot_br.model_index);
4273
4274        (lateral, Vec3::from(spec.foot_br.offset))
4275    }
4276}
4277
4278//////
4279#[derive(Deserialize)]
4280struct BirdLargeCentralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLACentralVoxSpec>);
4281impl_concatenate_for_wrapper!(BirdLargeCentralSpec);
4282
4283#[derive(Deserialize, Default)]
4284#[serde(default)]
4285struct SidedBLACentralVoxSpec {
4286    head: BirdLargeCentralSubSpec,
4287    beak: BirdLargeCentralSubSpec,
4288    neck: BirdLargeCentralSubSpec,
4289    chest: BirdLargeCentralSubSpec,
4290    tail_front: BirdLargeCentralSubSpec,
4291    tail_rear: BirdLargeCentralSubSpec,
4292}
4293
4294#[derive(Deserialize, Default)]
4295struct BirdLargeCentralSubSpec {
4296    offset: [f32; 3], // Should be relative to initial origin
4297    central: VoxSimple,
4298    #[serde(default)]
4299    model_index: u32,
4300}
4301
4302#[derive(Deserialize)]
4303struct BirdLargeLateralSpec(HashMap<(BLASpecies, BLABodyType), SidedBLALateralVoxSpec>);
4304impl_concatenate_for_wrapper!(BirdLargeLateralSpec);
4305
4306#[derive(Deserialize, Default)]
4307#[serde(default)]
4308struct SidedBLALateralVoxSpec {
4309    wing_in_l: BirdLargeLateralSubSpec,
4310    wing_in_r: BirdLargeLateralSubSpec,
4311    wing_mid_l: BirdLargeLateralSubSpec,
4312    wing_mid_r: BirdLargeLateralSubSpec,
4313    wing_out_l: BirdLargeLateralSubSpec,
4314    wing_out_r: BirdLargeLateralSubSpec,
4315    leg_l: BirdLargeLateralSubSpec,
4316    leg_r: BirdLargeLateralSubSpec,
4317    foot_l: BirdLargeLateralSubSpec,
4318    foot_r: BirdLargeLateralSubSpec,
4319}
4320
4321#[derive(Deserialize, Default)]
4322struct BirdLargeLateralSubSpec {
4323    offset: [f32; 3], // Should be relative to initial origin
4324    lateral: VoxSimple,
4325    #[serde(default)]
4326    model_index: u32,
4327}
4328
4329make_vox_spec!(
4330    bird_large::Body,
4331    struct BirdLargeSpec {
4332        central: BirdLargeCentralSpec = "voxygen.voxel.bird_large_central_manifest",
4333        lateral: BirdLargeLateralSpec = "voxygen.voxel.bird_large_lateral_manifest",
4334    },
4335    |FigureKey { body, extra, .. }, spec| {
4336        let third_person = extra
4337            .as_ref()
4338            .and_then(|loadout| loadout.third_person.as_ref());
4339
4340        [
4341            third_person.map(|_| {
4342                spec.central
4343                    .read()
4344                    .0
4345                    .mesh_head(body.species, body.body_type)
4346            }),
4347            third_person.map(|_| {
4348                spec.central
4349                    .read()
4350                    .0
4351                    .mesh_beak(body.species, body.body_type)
4352            }),
4353            Some(
4354                spec.central
4355                    .read()
4356                    .0
4357                    .mesh_neck(body.species, body.body_type),
4358            ),
4359            Some(
4360                spec.central
4361                    .read()
4362                    .0
4363                    .mesh_chest(body.species, body.body_type),
4364            ),
4365            Some(
4366                spec.central
4367                    .read()
4368                    .0
4369                    .mesh_tail_front(body.species, body.body_type),
4370            ),
4371            Some(
4372                spec.central
4373                    .read()
4374                    .0
4375                    .mesh_tail_rear(body.species, body.body_type),
4376            ),
4377            Some(
4378                spec.lateral
4379                    .read()
4380                    .0
4381                    .mesh_wing_in_l(body.species, body.body_type),
4382            ),
4383            Some(
4384                spec.lateral
4385                    .read()
4386                    .0
4387                    .mesh_wing_in_r(body.species, body.body_type),
4388            ),
4389            Some(
4390                spec.lateral
4391                    .read()
4392                    .0
4393                    .mesh_wing_mid_l(body.species, body.body_type),
4394            ),
4395            Some(
4396                spec.lateral
4397                    .read()
4398                    .0
4399                    .mesh_wing_mid_r(body.species, body.body_type),
4400            ),
4401            Some(
4402                spec.lateral
4403                    .read()
4404                    .0
4405                    .mesh_wing_out_l(body.species, body.body_type),
4406            ),
4407            Some(
4408                spec.lateral
4409                    .read()
4410                    .0
4411                    .mesh_wing_out_r(body.species, body.body_type),
4412            ),
4413            Some(
4414                spec.lateral
4415                    .read()
4416                    .0
4417                    .mesh_leg_l(body.species, body.body_type),
4418            ),
4419            Some(
4420                spec.lateral
4421                    .read()
4422                    .0
4423                    .mesh_leg_r(body.species, body.body_type),
4424            ),
4425            Some(
4426                spec.lateral
4427                    .read()
4428                    .0
4429                    .mesh_foot_l(body.species, body.body_type),
4430            ),
4431            Some(
4432                spec.lateral
4433                    .read()
4434                    .0
4435                    .mesh_foot_r(body.species, body.body_type),
4436            ),
4437        ]
4438    },
4439);
4440
4441impl BirdLargeCentralSpec {
4442    fn mesh_head(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4443        let spec = match self.0.get(&(species, body_type)) {
4444            Some(spec) => spec,
4445            None => {
4446                error!(
4447                    "No head specification exists for the combination of {:?} and {:?}",
4448                    species, body_type
4449                );
4450                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4451            },
4452        };
4453        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
4454
4455        (central, Vec3::from(spec.head.offset))
4456    }
4457
4458    fn mesh_beak(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4459        let spec = match self.0.get(&(species, body_type)) {
4460            Some(spec) => spec,
4461            None => {
4462                error!(
4463                    "No beak specification exists for the combination of {:?} and {:?}",
4464                    species, body_type
4465                );
4466                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4467            },
4468        };
4469        let central = graceful_load_segment(&spec.beak.central.0, spec.beak.model_index);
4470
4471        (central, Vec3::from(spec.beak.offset))
4472    }
4473
4474    fn mesh_neck(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4475        let spec = match self.0.get(&(species, body_type)) {
4476            Some(spec) => spec,
4477            None => {
4478                error!(
4479                    "No neck specification exists for the combination of {:?} and {:?}",
4480                    species, body_type
4481                );
4482                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4483            },
4484        };
4485        let central = graceful_load_segment(&spec.neck.central.0, spec.neck.model_index);
4486
4487        (central, Vec3::from(spec.neck.offset))
4488    }
4489
4490    fn mesh_chest(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4491        let spec = match self.0.get(&(species, body_type)) {
4492            Some(spec) => spec,
4493            None => {
4494                error!(
4495                    "No chest specification exists for the combination of {:?} and {:?}",
4496                    species, body_type
4497                );
4498                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4499            },
4500        };
4501        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
4502
4503        (central, Vec3::from(spec.chest.offset))
4504    }
4505
4506    fn mesh_tail_front(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4507        let spec = match self.0.get(&(species, body_type)) {
4508            Some(spec) => spec,
4509            None => {
4510                error!(
4511                    "No tail front specification exists for the combination of {:?} and {:?}",
4512                    species, body_type
4513                );
4514                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4515            },
4516        };
4517        let central =
4518            graceful_load_segment(&spec.tail_front.central.0, spec.tail_front.model_index);
4519
4520        (central, Vec3::from(spec.tail_front.offset))
4521    }
4522
4523    fn mesh_tail_rear(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4524        let spec = match self.0.get(&(species, body_type)) {
4525            Some(spec) => spec,
4526            None => {
4527                error!(
4528                    "No tail rear specification exists for the combination of {:?} and {:?}",
4529                    species, body_type
4530                );
4531                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4532            },
4533        };
4534        let central = graceful_load_segment(&spec.tail_rear.central.0, spec.tail_rear.model_index);
4535
4536        (central, Vec3::from(spec.tail_rear.offset))
4537    }
4538}
4539impl BirdLargeLateralSpec {
4540    fn mesh_wing_in_l(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4541        let spec = match self.0.get(&(species, body_type)) {
4542            Some(spec) => spec,
4543            None => {
4544                error!(
4545                    "No wing in in left specification exists for the combination of {:?} and {:?}",
4546                    species, body_type
4547                );
4548                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4549            },
4550        };
4551        let lateral = graceful_load_segment_flipped(
4552            &spec.wing_in_l.lateral.0,
4553            true,
4554            spec.wing_in_l.model_index,
4555        );
4556
4557        (lateral, Vec3::from(spec.wing_in_l.offset))
4558    }
4559
4560    fn mesh_wing_in_r(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4561        let spec = match self.0.get(&(species, body_type)) {
4562            Some(spec) => spec,
4563            None => {
4564                error!(
4565                    "No wing in right specification exists for the combination of {:?} and {:?}",
4566                    species, body_type
4567                );
4568                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4569            },
4570        };
4571        let lateral = graceful_load_segment(&spec.wing_in_r.lateral.0, spec.wing_in_r.model_index);
4572
4573        (lateral, Vec3::from(spec.wing_in_r.offset))
4574    }
4575
4576    fn mesh_wing_mid_l(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4577        let spec = match self.0.get(&(species, body_type)) {
4578            Some(spec) => spec,
4579            None => {
4580                error!(
4581                    "No wing mid specification exists for the combination of {:?} and {:?}",
4582                    species, body_type
4583                );
4584                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4585            },
4586        };
4587        let lateral = graceful_load_segment_flipped(
4588            &spec.wing_mid_l.lateral.0,
4589            true,
4590            spec.wing_mid_l.model_index,
4591        );
4592
4593        (lateral, Vec3::from(spec.wing_mid_l.offset))
4594    }
4595
4596    fn mesh_wing_mid_r(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4597        let spec = match self.0.get(&(species, body_type)) {
4598            Some(spec) => spec,
4599            None => {
4600                error!(
4601                    "No wing mid specification exists for the combination of {:?} and {:?}",
4602                    species, body_type
4603                );
4604                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4605            },
4606        };
4607        let lateral =
4608            graceful_load_segment(&spec.wing_mid_r.lateral.0, spec.wing_mid_r.model_index);
4609
4610        (lateral, Vec3::from(spec.wing_mid_r.offset))
4611    }
4612
4613    fn mesh_wing_out_l(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4614        let spec = match self.0.get(&(species, body_type)) {
4615            Some(spec) => spec,
4616            None => {
4617                error!(
4618                    "No wing out specification exists for the combination of {:?} and {:?}",
4619                    species, body_type
4620                );
4621                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4622            },
4623        };
4624        let lateral = graceful_load_segment_flipped(
4625            &spec.wing_out_l.lateral.0,
4626            true,
4627            spec.wing_out_l.model_index,
4628        );
4629
4630        (lateral, Vec3::from(spec.wing_out_l.offset))
4631    }
4632
4633    fn mesh_wing_out_r(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4634        let spec = match self.0.get(&(species, body_type)) {
4635            Some(spec) => spec,
4636            None => {
4637                error!(
4638                    "No wing out specification exists for the combination of {:?} and {:?}",
4639                    species, body_type
4640                );
4641                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4642            },
4643        };
4644        let lateral =
4645            graceful_load_segment(&spec.wing_out_r.lateral.0, spec.wing_out_r.model_index);
4646
4647        (lateral, Vec3::from(spec.wing_out_r.offset))
4648    }
4649
4650    fn mesh_leg_l(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4651        let spec = match self.0.get(&(species, body_type)) {
4652            Some(spec) => spec,
4653            None => {
4654                error!(
4655                    "No leg specification exists for the combination of {:?} and {:?}",
4656                    species, body_type
4657                );
4658                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4659            },
4660        };
4661        let lateral =
4662            graceful_load_segment_flipped(&spec.leg_l.lateral.0, true, spec.leg_l.model_index);
4663
4664        (lateral, Vec3::from(spec.leg_l.offset))
4665    }
4666
4667    fn mesh_leg_r(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4668        let spec = match self.0.get(&(species, body_type)) {
4669            Some(spec) => spec,
4670            None => {
4671                error!(
4672                    "No leg specification exists for the combination of {:?} and {:?}",
4673                    species, body_type
4674                );
4675                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4676            },
4677        };
4678        let lateral = graceful_load_segment(&spec.leg_r.lateral.0, spec.leg_r.model_index);
4679
4680        (lateral, Vec3::from(spec.leg_r.offset))
4681    }
4682
4683    fn mesh_foot_l(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4684        let spec = match self.0.get(&(species, body_type)) {
4685            Some(spec) => spec,
4686            None => {
4687                error!(
4688                    "No foot specification exists for the combination of {:?} and {:?}",
4689                    species, body_type
4690                );
4691                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4692            },
4693        };
4694        let lateral =
4695            graceful_load_segment_flipped(&spec.foot_l.lateral.0, true, spec.foot_l.model_index);
4696
4697        (lateral, Vec3::from(spec.foot_l.offset))
4698    }
4699
4700    fn mesh_foot_r(&self, species: BLASpecies, body_type: BLABodyType) -> BoneMeshes {
4701        let spec = match self.0.get(&(species, body_type)) {
4702            Some(spec) => spec,
4703            None => {
4704                error!(
4705                    "No foot specification exists for the combination of {:?} and {:?}",
4706                    species, body_type
4707                );
4708                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4709            },
4710        };
4711        let lateral = graceful_load_segment(&spec.foot_r.lateral.0, spec.foot_r.model_index);
4712
4713        (lateral, Vec3::from(spec.foot_r.offset))
4714    }
4715}
4716
4717//////
4718#[derive(Deserialize)]
4719struct BipedLargeCentralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLCentralVoxSpec>);
4720impl_concatenate_for_wrapper!(BipedLargeCentralSpec);
4721
4722#[derive(Deserialize, Default)]
4723#[serde(default)]
4724struct SidedBLCentralVoxSpec {
4725    head: BipedLargeCentralSubSpec,
4726    jaw: BipedLargeCentralSubSpec,
4727    torso_upper: BipedLargeCentralSubSpec,
4728    torso_lower: BipedLargeCentralSubSpec,
4729    tail: BipedLargeCentralSubSpec,
4730}
4731#[derive(Deserialize, Default)]
4732struct BipedLargeCentralSubSpec {
4733    offset: [f32; 3], // Should be relative to initial origin
4734    central: VoxSimple,
4735    #[serde(default)]
4736    model_index: u32,
4737}
4738
4739#[derive(Deserialize)]
4740struct BipedLargeLateralSpec(HashMap<(BLSpecies, BLBodyType), SidedBLLateralVoxSpec>);
4741impl_concatenate_for_wrapper!(BipedLargeLateralSpec);
4742
4743#[derive(Deserialize, Default)]
4744#[serde(default)]
4745struct SidedBLLateralVoxSpec {
4746    shoulder_l: BipedLargeLateralSubSpec,
4747    shoulder_r: BipedLargeLateralSubSpec,
4748    hand_l: BipedLargeLateralSubSpec,
4749    hand_r: BipedLargeLateralSubSpec,
4750    leg_l: BipedLargeLateralSubSpec,
4751    leg_r: BipedLargeLateralSubSpec,
4752    foot_l: BipedLargeLateralSubSpec,
4753    foot_r: BipedLargeLateralSubSpec,
4754}
4755
4756#[derive(Deserialize, Default)]
4757struct BipedLargeLateralSubSpec {
4758    offset: [f32; 3], // Should be relative to initial origin
4759    lateral: VoxSimple,
4760    #[serde(default)]
4761    model_index: u32,
4762}
4763
4764#[derive(Deserialize)]
4765struct BipedLargeMainSpec(HashMap<ToolKey, ArmorVoxSpec>);
4766impl_concatenate_for_wrapper!(BipedLargeMainSpec);
4767
4768#[derive(Deserialize)]
4769struct BipedLargeSecondSpec(HashMap<ToolKey, ArmorVoxSpec>);
4770impl_concatenate_for_wrapper!(BipedLargeSecondSpec);
4771
4772make_vox_spec!(
4773    biped_large::Body,
4774    struct BipedLargeSpec {
4775        central: BipedLargeCentralSpec = "voxygen.voxel.biped_large_central_manifest",
4776        lateral: BipedLargeLateralSpec = "voxygen.voxel.biped_large_lateral_manifest",
4777        main: BipedLargeMainSpec = "voxygen.voxel.biped_weapon_manifest",
4778        second: BipedLargeSecondSpec = "voxygen.voxel.biped_weapon_manifest",
4779    },
4780    |FigureKey {
4781         body,
4782         item_key: _,
4783         extra,
4784     },
4785     spec| {
4786        const DEFAULT_LOADOUT: super::cache::CharacterCacheKey = super::cache::CharacterCacheKey {
4787            third_person: None,
4788            tool: None,
4789            lantern: None,
4790            glider: None,
4791            hand: None,
4792            foot: None,
4793            head: None,
4794        };
4795
4796        // TODO: This is bad code, maybe this method should return Option<_>
4797        let loadout = extra.as_deref().unwrap_or(&DEFAULT_LOADOUT);
4798        let third_person = loadout.third_person.as_ref();
4799
4800        //let third_person = loadout.third_person.as_ref();
4801        let tool = loadout.tool.as_ref();
4802        [
4803            third_person.map(|_| {
4804                spec.central
4805                    .read()
4806                    .0
4807                    .mesh_head(body.species, body.body_type)
4808            }),
4809            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
4810            third_person.map(|_| {
4811                spec.central
4812                    .read()
4813                    .0
4814                    .mesh_torso_upper(body.species, body.body_type)
4815            }),
4816            Some(
4817                spec.central
4818                    .read()
4819                    .0
4820                    .mesh_torso_lower(body.species, body.body_type),
4821            ),
4822            Some(
4823                spec.central
4824                    .read()
4825                    .0
4826                    .mesh_tail(body.species, body.body_type),
4827            ),
4828            tool.and_then(|tool| tool.active.as_ref())
4829                .map(|tool| spec.main.read().0.mesh_main(tool, false)),
4830            tool.and_then(|tool| tool.active.as_ref())
4831                .map(|tool| spec.second.read().0.mesh_second(tool, false)),
4832            Some(
4833                spec.lateral
4834                    .read()
4835                    .0
4836                    .mesh_shoulder_l(body.species, body.body_type),
4837            ),
4838            Some(
4839                spec.lateral
4840                    .read()
4841                    .0
4842                    .mesh_shoulder_r(body.species, body.body_type),
4843            ),
4844            Some(
4845                spec.lateral
4846                    .read()
4847                    .0
4848                    .mesh_hand_l(body.species, body.body_type),
4849            ),
4850            Some(
4851                spec.lateral
4852                    .read()
4853                    .0
4854                    .mesh_hand_r(body.species, body.body_type),
4855            ),
4856            Some(
4857                spec.lateral
4858                    .read()
4859                    .0
4860                    .mesh_leg_l(body.species, body.body_type),
4861            ),
4862            Some(
4863                spec.lateral
4864                    .read()
4865                    .0
4866                    .mesh_leg_r(body.species, body.body_type),
4867            ),
4868            Some(
4869                spec.lateral
4870                    .read()
4871                    .0
4872                    .mesh_foot_l(body.species, body.body_type),
4873            ),
4874            Some(
4875                spec.lateral
4876                    .read()
4877                    .0
4878                    .mesh_foot_r(body.species, body.body_type),
4879            ),
4880            Some(mesh_hold()),
4881        ]
4882    },
4883);
4884
4885impl BipedLargeCentralSpec {
4886    fn mesh_head(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4887        let spec = match self.0.get(&(species, body_type)) {
4888            Some(spec) => spec,
4889            None => {
4890                error!(
4891                    "No head specification exists for the combination of {:?} and {:?}",
4892                    species, body_type
4893                );
4894                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4895            },
4896        };
4897        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
4898
4899        (central, Vec3::from(spec.head.offset))
4900    }
4901
4902    fn mesh_jaw(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4903        let spec = match self.0.get(&(species, body_type)) {
4904            Some(spec) => spec,
4905            None => {
4906                error!(
4907                    "No jaw specification exists for the combination of {:?} and {:?}",
4908                    species, body_type
4909                );
4910                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4911            },
4912        };
4913        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
4914
4915        (central, Vec3::from(spec.jaw.offset))
4916    }
4917
4918    fn mesh_torso_upper(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4919        let spec = match self.0.get(&(species, body_type)) {
4920            Some(spec) => spec,
4921            None => {
4922                error!(
4923                    "No torso upper specification exists for the combination of {:?} and {:?}",
4924                    species, body_type
4925                );
4926                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4927            },
4928        };
4929        let central =
4930            graceful_load_segment(&spec.torso_upper.central.0, spec.torso_upper.model_index);
4931
4932        (central, Vec3::from(spec.torso_upper.offset))
4933    }
4934
4935    fn mesh_torso_lower(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4936        let spec = match self.0.get(&(species, body_type)) {
4937            Some(spec) => spec,
4938            None => {
4939                error!(
4940                    "No torso lower specification exists for the combination of {:?} and {:?}",
4941                    species, body_type
4942                );
4943                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4944            },
4945        };
4946        let central =
4947            graceful_load_segment(&spec.torso_lower.central.0, spec.torso_lower.model_index);
4948
4949        (central, Vec3::from(spec.torso_lower.offset))
4950    }
4951
4952    fn mesh_tail(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4953        let spec = match self.0.get(&(species, body_type)) {
4954            Some(spec) => spec,
4955            None => {
4956                error!(
4957                    "No tail specification exists for the combination of {:?} and {:?}",
4958                    species, body_type
4959                );
4960                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4961            },
4962        };
4963        let central = graceful_load_segment(&spec.tail.central.0, spec.tail.model_index);
4964
4965        (central, Vec3::from(spec.tail.offset))
4966    }
4967}
4968impl BipedLargeLateralSpec {
4969    fn mesh_shoulder_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4970        let spec = match self.0.get(&(species, body_type)) {
4971            Some(spec) => spec,
4972            None => {
4973                error!(
4974                    "No shoulder specification exists for the combination of {:?} and {:?}",
4975                    species, body_type
4976                );
4977                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4978            },
4979        };
4980        let lateral =
4981            graceful_load_segment(&spec.shoulder_l.lateral.0, spec.shoulder_l.model_index);
4982
4983        (lateral, Vec3::from(spec.shoulder_l.offset))
4984    }
4985
4986    fn mesh_shoulder_r(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
4987        let spec = match self.0.get(&(species, body_type)) {
4988            Some(spec) => spec,
4989            None => {
4990                error!(
4991                    "No shoulder specification exists for the combination of {:?} and {:?}",
4992                    species, body_type
4993                );
4994                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
4995            },
4996        };
4997        let lateral =
4998            graceful_load_segment(&spec.shoulder_r.lateral.0, spec.shoulder_r.model_index);
4999
5000        (lateral, Vec3::from(spec.shoulder_r.offset))
5001    }
5002
5003    fn mesh_hand_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5004        let spec = match self.0.get(&(species, body_type)) {
5005            Some(spec) => spec,
5006            None => {
5007                error!(
5008                    "No hand specification exists for the combination of {:?} and {:?}",
5009                    species, body_type
5010                );
5011                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5012            },
5013        };
5014        let lateral = graceful_load_segment(&spec.hand_l.lateral.0, spec.hand_l.model_index);
5015
5016        (lateral, Vec3::from(spec.hand_l.offset))
5017    }
5018
5019    fn mesh_hand_r(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5020        let spec = match self.0.get(&(species, body_type)) {
5021            Some(spec) => spec,
5022            None => {
5023                error!(
5024                    "No hand specification exists for the combination of {:?} and {:?}",
5025                    species, body_type
5026                );
5027                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5028            },
5029        };
5030        let lateral = graceful_load_segment(&spec.hand_r.lateral.0, spec.hand_r.model_index);
5031
5032        (lateral, Vec3::from(spec.hand_r.offset))
5033    }
5034
5035    fn mesh_leg_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5036        let spec = match self.0.get(&(species, body_type)) {
5037            Some(spec) => spec,
5038            None => {
5039                error!(
5040                    "No leg specification exists for the combination of {:?} and {:?}",
5041                    species, body_type
5042                );
5043                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5044            },
5045        };
5046        let lateral = graceful_load_segment(&spec.leg_l.lateral.0, spec.leg_l.model_index);
5047
5048        (lateral, Vec3::from(spec.leg_l.offset))
5049    }
5050
5051    fn mesh_leg_r(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5052        let spec = match self.0.get(&(species, body_type)) {
5053            Some(spec) => spec,
5054            None => {
5055                error!(
5056                    "No leg specification exists for the combination of {:?} and {:?}",
5057                    species, body_type
5058                );
5059                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5060            },
5061        };
5062        let lateral = graceful_load_segment(&spec.leg_r.lateral.0, spec.leg_r.model_index);
5063
5064        (lateral, Vec3::from(spec.leg_r.offset))
5065    }
5066
5067    fn mesh_foot_l(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5068        let spec = match self.0.get(&(species, body_type)) {
5069            Some(spec) => spec,
5070            None => {
5071                error!(
5072                    "No foot specification exists for the combination of {:?} and {:?}",
5073                    species, body_type
5074                );
5075                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5076            },
5077        };
5078        let lateral = graceful_load_segment(&spec.foot_l.lateral.0, spec.foot_l.model_index);
5079
5080        (lateral, Vec3::from(spec.foot_l.offset))
5081    }
5082
5083    fn mesh_foot_r(&self, species: BLSpecies, body_type: BLBodyType) -> BoneMeshes {
5084        let spec = match self.0.get(&(species, body_type)) {
5085            Some(spec) => spec,
5086            None => {
5087                error!(
5088                    "No foot specification exists for the combination of {:?} and {:?}",
5089                    species, body_type
5090                );
5091                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5092            },
5093        };
5094        let lateral = graceful_load_segment(&spec.foot_r.lateral.0, spec.foot_r.model_index);
5095
5096        (lateral, Vec3::from(spec.foot_r.offset))
5097    }
5098}
5099impl BipedLargeMainSpec {
5100    fn mesh_main(&self, tool: &ToolKey, flipped: bool) -> BoneMeshes {
5101        let spec = match self.0.get(tool) {
5102            Some(spec) => spec,
5103            None => {
5104                error!(?tool, "No tool/weapon specification exists");
5105                return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
5106            },
5107        };
5108
5109        let tool_kind_segment = if flipped {
5110            graceful_load_segment_flipped(&spec.vox_spec.0, true, spec.vox_spec.2)
5111        } else {
5112            graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2)
5113        };
5114
5115        let offset = Vec3::new(
5116            if flipped {
5117                0.0 - spec.vox_spec.1[0] - (tool_kind_segment.sz.x as f32)
5118            } else {
5119                spec.vox_spec.1[0]
5120            },
5121            spec.vox_spec.1[1],
5122            spec.vox_spec.1[2],
5123        );
5124
5125        (tool_kind_segment, offset)
5126    }
5127}
5128impl BipedLargeSecondSpec {
5129    fn mesh_second(&self, tool: &ToolKey, flipped: bool) -> BoneMeshes {
5130        let spec = match self.0.get(tool) {
5131            Some(spec) => spec,
5132            None => {
5133                error!(?tool, "No tool/weapon specification exists");
5134                return load_mesh("not_found", Vec3::new(-1.5, -1.5, -7.0));
5135            },
5136        };
5137
5138        let tool_kind_segment = if flipped {
5139            graceful_load_segment_flipped(&spec.vox_spec.0, true, spec.vox_spec.2)
5140        } else {
5141            graceful_load_segment(&spec.vox_spec.0, spec.vox_spec.2)
5142        };
5143
5144        let offset = Vec3::new(
5145            if flipped {
5146                0.0 - spec.vox_spec.1[0] - (tool_kind_segment.sz.x as f32)
5147            } else {
5148                spec.vox_spec.1[0]
5149            },
5150            spec.vox_spec.1[1],
5151            spec.vox_spec.1[2],
5152        );
5153
5154        (tool_kind_segment, offset)
5155    }
5156}
5157
5158//////
5159#[derive(Deserialize)]
5160struct GolemCentralSpec(HashMap<(GSpecies, GBodyType), SidedGCentralVoxSpec>);
5161impl_concatenate_for_wrapper!(GolemCentralSpec);
5162
5163#[derive(Deserialize, Default)]
5164#[serde(default)]
5165struct SidedGCentralVoxSpec {
5166    head: GolemCentralSubSpec,
5167    jaw: GolemCentralSubSpec,
5168    torso_upper: GolemCentralSubSpec,
5169    torso_lower: GolemCentralSubSpec,
5170}
5171
5172#[derive(Deserialize, Default)]
5173struct GolemCentralSubSpec {
5174    offset: [f32; 3], // Should be relative to initial origin
5175    central: VoxSimple,
5176    #[serde(default)]
5177    model_index: u32,
5178}
5179
5180#[derive(Deserialize)]
5181struct GolemLateralSpec(HashMap<(GSpecies, GBodyType), SidedGLateralVoxSpec>);
5182impl_concatenate_for_wrapper!(GolemLateralSpec);
5183
5184#[derive(Deserialize, Default)]
5185#[serde(default)]
5186struct SidedGLateralVoxSpec {
5187    shoulder_l: GolemLateralSubSpec,
5188    shoulder_r: GolemLateralSubSpec,
5189    hand_l: GolemLateralSubSpec,
5190    hand_r: GolemLateralSubSpec,
5191    leg_l: GolemLateralSubSpec,
5192    leg_r: GolemLateralSubSpec,
5193    foot_l: GolemLateralSubSpec,
5194    foot_r: GolemLateralSubSpec,
5195}
5196
5197#[derive(Deserialize, Default)]
5198struct GolemLateralSubSpec {
5199    offset: [f32; 3], // Should be relative to initial origin
5200    lateral: VoxSimple,
5201    #[serde(default)]
5202    model_index: u32,
5203}
5204
5205make_vox_spec!(
5206    golem::Body,
5207    struct GolemSpec {
5208        central: GolemCentralSpec = "voxygen.voxel.golem_central_manifest",
5209        lateral: GolemLateralSpec = "voxygen.voxel.golem_lateral_manifest",
5210    },
5211    |FigureKey { body, extra, .. }, spec| {
5212        let third_person = extra
5213            .as_ref()
5214            .and_then(|loadout| loadout.third_person.as_ref());
5215
5216        [
5217            third_person.map(|_| {
5218                spec.central
5219                    .read()
5220                    .0
5221                    .mesh_head(body.species, body.body_type)
5222            }),
5223            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
5224            Some(
5225                spec.central
5226                    .read()
5227                    .0
5228                    .mesh_torso_upper(body.species, body.body_type),
5229            ),
5230            Some(
5231                spec.central
5232                    .read()
5233                    .0
5234                    .mesh_torso_lower(body.species, body.body_type),
5235            ),
5236            Some(
5237                spec.lateral
5238                    .read()
5239                    .0
5240                    .mesh_shoulder_l(body.species, body.body_type),
5241            ),
5242            Some(
5243                spec.lateral
5244                    .read()
5245                    .0
5246                    .mesh_shoulder_r(body.species, body.body_type),
5247            ),
5248            Some(
5249                spec.lateral
5250                    .read()
5251                    .0
5252                    .mesh_hand_l(body.species, body.body_type),
5253            ),
5254            Some(
5255                spec.lateral
5256                    .read()
5257                    .0
5258                    .mesh_hand_r(body.species, body.body_type),
5259            ),
5260            Some(
5261                spec.lateral
5262                    .read()
5263                    .0
5264                    .mesh_leg_l(body.species, body.body_type),
5265            ),
5266            Some(
5267                spec.lateral
5268                    .read()
5269                    .0
5270                    .mesh_leg_r(body.species, body.body_type),
5271            ),
5272            Some(
5273                spec.lateral
5274                    .read()
5275                    .0
5276                    .mesh_foot_l(body.species, body.body_type),
5277            ),
5278            Some(
5279                spec.lateral
5280                    .read()
5281                    .0
5282                    .mesh_foot_r(body.species, body.body_type),
5283            ),
5284            None,
5285            None,
5286            None,
5287            None,
5288        ]
5289    },
5290);
5291
5292impl GolemCentralSpec {
5293    fn mesh_head(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5294        let spec = match self.0.get(&(species, body_type)) {
5295            Some(spec) => spec,
5296            None => {
5297                error!(
5298                    "No head specification exists for the combination of {:?} and {:?}",
5299                    species, body_type
5300                );
5301                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5302            },
5303        };
5304        let central = graceful_load_segment(&spec.head.central.0, spec.head.model_index);
5305
5306        (central, Vec3::from(spec.head.offset))
5307    }
5308
5309    fn mesh_jaw(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5310        let spec = match self.0.get(&(species, body_type)) {
5311            Some(spec) => spec,
5312            None => {
5313                error!(
5314                    "No jaw specification exists for the combination of {:?} and {:?}",
5315                    species, body_type
5316                );
5317                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5318            },
5319        };
5320        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
5321
5322        (central, Vec3::from(spec.jaw.offset))
5323    }
5324
5325    fn mesh_torso_upper(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5326        let spec = match self.0.get(&(species, body_type)) {
5327            Some(spec) => spec,
5328            None => {
5329                error!(
5330                    "No torso upper specification exists for the combination of {:?} and {:?}",
5331                    species, body_type
5332                );
5333                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5334            },
5335        };
5336        let central =
5337            graceful_load_segment(&spec.torso_upper.central.0, spec.torso_upper.model_index);
5338
5339        (central, Vec3::from(spec.torso_upper.offset))
5340    }
5341
5342    pub fn mesh_torso_lower(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5343        let spec = match self.0.get(&(species, body_type)) {
5344            Some(spec) => spec,
5345            None => {
5346                error!(
5347                    "No torso lower specification exists for the combination of {:?} and {:?}",
5348                    species, body_type
5349                );
5350                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5351            },
5352        };
5353        let central =
5354            graceful_load_segment(&spec.torso_lower.central.0, spec.torso_lower.model_index);
5355
5356        (central, Vec3::from(spec.torso_lower.offset))
5357    }
5358}
5359impl GolemLateralSpec {
5360    fn mesh_shoulder_l(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5361        let spec = match self.0.get(&(species, body_type)) {
5362            Some(spec) => spec,
5363            None => {
5364                error!(
5365                    "No shoulder specification exists for the combination of {:?} and {:?}",
5366                    species, body_type
5367                );
5368                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5369            },
5370        };
5371        let lateral =
5372            graceful_load_segment(&spec.shoulder_l.lateral.0, spec.shoulder_l.model_index);
5373
5374        (lateral, Vec3::from(spec.shoulder_l.offset))
5375    }
5376
5377    fn mesh_shoulder_r(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5378        let spec = match self.0.get(&(species, body_type)) {
5379            Some(spec) => spec,
5380            None => {
5381                error!(
5382                    "No shoulder specification exists for the combination of {:?} and {:?}",
5383                    species, body_type
5384                );
5385                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5386            },
5387        };
5388        let lateral =
5389            graceful_load_segment(&spec.shoulder_r.lateral.0, spec.shoulder_r.model_index);
5390
5391        (lateral, Vec3::from(spec.shoulder_r.offset))
5392    }
5393
5394    fn mesh_hand_l(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5395        let spec = match self.0.get(&(species, body_type)) {
5396            Some(spec) => spec,
5397            None => {
5398                error!(
5399                    "No hand specification exists for the combination of {:?} and {:?}",
5400                    species, body_type
5401                );
5402                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5403            },
5404        };
5405        let lateral = graceful_load_segment(&spec.hand_l.lateral.0, spec.hand_l.model_index);
5406
5407        (lateral, Vec3::from(spec.hand_l.offset))
5408    }
5409
5410    fn mesh_hand_r(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5411        let spec = match self.0.get(&(species, body_type)) {
5412            Some(spec) => spec,
5413            None => {
5414                error!(
5415                    "No hand specification exists for the combination of {:?} and {:?}",
5416                    species, body_type
5417                );
5418                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5419            },
5420        };
5421        let lateral = graceful_load_segment(&spec.hand_r.lateral.0, spec.hand_r.model_index);
5422
5423        (lateral, Vec3::from(spec.hand_r.offset))
5424    }
5425
5426    fn mesh_leg_l(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5427        let spec = match self.0.get(&(species, body_type)) {
5428            Some(spec) => spec,
5429            None => {
5430                error!(
5431                    "No leg specification exists for the combination of {:?} and {:?}",
5432                    species, body_type
5433                );
5434                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5435            },
5436        };
5437        let lateral = graceful_load_segment(&spec.leg_l.lateral.0, spec.leg_l.model_index);
5438
5439        (lateral, Vec3::from(spec.leg_l.offset))
5440    }
5441
5442    fn mesh_leg_r(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5443        let spec = match self.0.get(&(species, body_type)) {
5444            Some(spec) => spec,
5445            None => {
5446                error!(
5447                    "No leg specification exists for the combination of {:?} and {:?}",
5448                    species, body_type
5449                );
5450                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5451            },
5452        };
5453        let lateral = graceful_load_segment(&spec.leg_r.lateral.0, spec.leg_r.model_index);
5454
5455        (lateral, Vec3::from(spec.leg_r.offset))
5456    }
5457
5458    fn mesh_foot_l(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5459        let spec = match self.0.get(&(species, body_type)) {
5460            Some(spec) => spec,
5461            None => {
5462                error!(
5463                    "No foot specification exists for the combination of {:?} and {:?}",
5464                    species, body_type
5465                );
5466                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5467            },
5468        };
5469        let lateral = graceful_load_segment(&spec.foot_l.lateral.0, spec.foot_l.model_index);
5470
5471        (lateral, Vec3::from(spec.foot_l.offset))
5472    }
5473
5474    fn mesh_foot_r(&self, species: GSpecies, body_type: GBodyType) -> BoneMeshes {
5475        let spec = match self.0.get(&(species, body_type)) {
5476            Some(spec) => spec,
5477            None => {
5478                error!(
5479                    "No foot specification exists for the combination of {:?} and {:?}",
5480                    species, body_type
5481                );
5482                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5483            },
5484        };
5485        let lateral = graceful_load_segment(&spec.foot_r.lateral.0, spec.foot_r.model_index);
5486
5487        (lateral, Vec3::from(spec.foot_r.offset))
5488    }
5489}
5490
5491//////
5492#[derive(Deserialize)]
5493struct QuadrupedLowCentralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLCentralVoxSpec>);
5494impl_concatenate_for_wrapper!(QuadrupedLowCentralSpec);
5495
5496#[derive(Deserialize, Default)]
5497#[serde(default)]
5498struct SidedQLCentralVoxSpec {
5499    upper: QuadrupedLowCentralSubSpec,
5500    lower: QuadrupedLowCentralSubSpec,
5501    jaw: QuadrupedLowCentralSubSpec,
5502    chest: QuadrupedLowCentralSubSpec,
5503    tail_front: QuadrupedLowCentralSubSpec,
5504    tail_rear: QuadrupedLowCentralSubSpec,
5505}
5506
5507#[derive(Deserialize, Default)]
5508struct QuadrupedLowCentralSubSpec {
5509    offset: [f32; 3], // Should be relative to initial origin
5510    central: VoxSimple,
5511    #[serde(default)]
5512    model_index: u32,
5513}
5514
5515#[derive(Deserialize)]
5516struct QuadrupedLowLateralSpec(HashMap<(QLSpecies, QLBodyType), SidedQLLateralVoxSpec>);
5517impl_concatenate_for_wrapper!(QuadrupedLowLateralSpec);
5518
5519#[derive(Deserialize, Default)]
5520#[serde(default)]
5521struct SidedQLLateralVoxSpec {
5522    left_upper: QuadrupedLowLateralSubSpec,
5523    left_lower: QuadrupedLowLateralSubSpec,
5524    left_jaw: QuadrupedLowLateralSubSpec,
5525    right_upper: QuadrupedLowLateralSubSpec,
5526    right_lower: QuadrupedLowLateralSubSpec,
5527    right_jaw: QuadrupedLowLateralSubSpec,
5528    front_left: QuadrupedLowLateralSubSpec,
5529    front_right: QuadrupedLowLateralSubSpec,
5530    back_left: QuadrupedLowLateralSubSpec,
5531    back_right: QuadrupedLowLateralSubSpec,
5532}
5533#[derive(Deserialize, Default)]
5534struct QuadrupedLowLateralSubSpec {
5535    offset: [f32; 3], // Should be relative to initial origin
5536    lateral: VoxMirror,
5537    #[serde(default)]
5538    model_index: u32,
5539}
5540
5541make_vox_spec!(
5542    quadruped_low::Body,
5543    struct QuadrupedLowSpec {
5544        central: QuadrupedLowCentralSpec = "voxygen.voxel.quadruped_low_central_manifest",
5545        lateral: QuadrupedLowLateralSpec = "voxygen.voxel.quadruped_low_lateral_manifest",
5546    },
5547    |FigureKey { body, extra, .. }, spec| {
5548        let third_person = extra
5549            .as_ref()
5550            .and_then(|loadout| loadout.third_person.as_ref());
5551
5552        [
5553            third_person.map(|_| {
5554                spec.central
5555                    .read()
5556                    .0
5557                    .mesh_head_upper(body.species, body.body_type)
5558            }),
5559            third_person.map(|_| {
5560                spec.central
5561                    .read()
5562                    .0
5563                    .mesh_head_lower(body.species, body.body_type)
5564            }),
5565            third_person.map(|_| spec.central.read().0.mesh_jaw(body.species, body.body_type)),
5566            Some(
5567                spec.lateral
5568                    .read()
5569                    .0
5570                    .mesh_left_head_upper(body.species, body.body_type),
5571            ),
5572            Some(
5573                spec.lateral
5574                    .read()
5575                    .0
5576                    .mesh_left_head_lower(body.species, body.body_type),
5577            ),
5578            Some(
5579                spec.lateral
5580                    .read()
5581                    .0
5582                    .mesh_left_jaw(body.species, body.body_type),
5583            ),
5584            Some(
5585                spec.lateral
5586                    .read()
5587                    .0
5588                    .mesh_right_head_upper(body.species, body.body_type),
5589            ),
5590            Some(
5591                spec.lateral
5592                    .read()
5593                    .0
5594                    .mesh_right_head_lower(body.species, body.body_type),
5595            ),
5596            Some(
5597                spec.lateral
5598                    .read()
5599                    .0
5600                    .mesh_right_jaw(body.species, body.body_type),
5601            ),
5602            Some(
5603                spec.central
5604                    .read()
5605                    .0
5606                    .mesh_chest(body.species, body.body_type),
5607            ),
5608            Some(
5609                spec.central
5610                    .read()
5611                    .0
5612                    .mesh_tail_front(body.species, body.body_type),
5613            ),
5614            Some(
5615                spec.central
5616                    .read()
5617                    .0
5618                    .mesh_tail_rear(body.species, body.body_type),
5619            ),
5620            Some(
5621                spec.lateral
5622                    .read()
5623                    .0
5624                    .mesh_foot_fl(body.species, body.body_type),
5625            ),
5626            Some(
5627                spec.lateral
5628                    .read()
5629                    .0
5630                    .mesh_foot_fr(body.species, body.body_type),
5631            ),
5632            Some(
5633                spec.lateral
5634                    .read()
5635                    .0
5636                    .mesh_foot_bl(body.species, body.body_type),
5637            ),
5638            Some(
5639                spec.lateral
5640                    .read()
5641                    .0
5642                    .mesh_foot_br(body.species, body.body_type),
5643            ),
5644        ]
5645    },
5646);
5647
5648impl QuadrupedLowCentralSpec {
5649    fn mesh_head_upper(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5650        let spec = match self.0.get(&(species, body_type)) {
5651            Some(spec) => spec,
5652            None => {
5653                error!(
5654                    "No upper head specification exists for the combination of {:?} and {:?}",
5655                    species, body_type
5656                );
5657                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5658            },
5659        };
5660        let central = graceful_load_segment(&spec.upper.central.0, spec.upper.model_index);
5661
5662        (central, Vec3::from(spec.upper.offset))
5663    }
5664
5665    fn mesh_head_lower(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5666        let spec = match self.0.get(&(species, body_type)) {
5667            Some(spec) => spec,
5668            None => {
5669                error!(
5670                    "No lower head specification exists for the combination of {:?} and {:?}",
5671                    species, body_type
5672                );
5673                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5674            },
5675        };
5676        let central = graceful_load_segment(&spec.lower.central.0, spec.lower.model_index);
5677
5678        (central, Vec3::from(spec.lower.offset))
5679    }
5680
5681    fn mesh_jaw(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5682        let spec = match self.0.get(&(species, body_type)) {
5683            Some(spec) => spec,
5684            None => {
5685                error!(
5686                    "No jaw specification exists for the combination of {:?} and {:?}",
5687                    species, body_type
5688                );
5689                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5690            },
5691        };
5692        let central = graceful_load_segment(&spec.jaw.central.0, spec.jaw.model_index);
5693
5694        (central, Vec3::from(spec.jaw.offset))
5695    }
5696
5697    fn mesh_chest(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5698        let spec = match self.0.get(&(species, body_type)) {
5699            Some(spec) => spec,
5700            None => {
5701                error!(
5702                    "No chest specification exists for the combination of {:?} and {:?}",
5703                    species, body_type
5704                );
5705                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5706            },
5707        };
5708        let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
5709
5710        (central, Vec3::from(spec.chest.offset))
5711    }
5712
5713    fn mesh_tail_rear(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5714        let spec = match self.0.get(&(species, body_type)) {
5715            Some(spec) => spec,
5716            None => {
5717                error!(
5718                    "No tail_rear specification exists for the combination of {:?} and {:?}",
5719                    species, body_type
5720                );
5721                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5722            },
5723        };
5724        let central = graceful_load_segment(&spec.tail_rear.central.0, spec.tail_rear.model_index);
5725
5726        (central, Vec3::from(spec.tail_rear.offset))
5727    }
5728
5729    fn mesh_tail_front(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5730        let spec = match self.0.get(&(species, body_type)) {
5731            Some(spec) => spec,
5732            None => {
5733                error!(
5734                    "No tail_front specification exists for the combination of {:?} and {:?}",
5735                    species, body_type
5736                );
5737                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5738            },
5739        };
5740        let central =
5741            graceful_load_segment(&spec.tail_front.central.0, spec.tail_front.model_index);
5742
5743        (central, Vec3::from(spec.tail_front.offset))
5744    }
5745}
5746
5747impl QuadrupedLowLateralSpec {
5748    fn mesh_left_head_upper(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5749        let spec = match self.0.get(&(species, body_type)) {
5750            Some(spec) => spec,
5751            None => {
5752                error!(
5753                    "No left upper head specification exists for the combination of {:?} and {:?}",
5754                    species, body_type
5755                );
5756                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5757            },
5758        };
5759
5760        let latspec = &spec.left_upper.lateral;
5761        let lateral =
5762            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.left_upper.model_index);
5763
5764        (lateral, Vec3::from(spec.left_upper.offset))
5765    }
5766
5767    fn mesh_left_head_lower(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5768        let spec = match self.0.get(&(species, body_type)) {
5769            Some(spec) => spec,
5770            None => {
5771                error!(
5772                    "No left lower head specification exists for the combination of {:?} and {:?}",
5773                    species, body_type
5774                );
5775                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5776            },
5777        };
5778
5779        let latspec = &spec.left_lower.lateral;
5780        let lateral =
5781            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.left_lower.model_index);
5782
5783        (lateral, Vec3::from(spec.left_lower.offset))
5784    }
5785
5786    fn mesh_left_jaw(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5787        let spec = match self.0.get(&(species, body_type)) {
5788            Some(spec) => spec,
5789            None => {
5790                error!(
5791                    "No left jaw specification exists for the combination of {:?} and {:?}",
5792                    species, body_type
5793                );
5794                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5795            },
5796        };
5797
5798        let latspec = &spec.left_jaw.lateral;
5799        let lateral =
5800            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.left_jaw.model_index);
5801
5802        (lateral, Vec3::from(spec.left_jaw.offset))
5803    }
5804
5805    fn mesh_right_head_upper(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5806        let spec = match self.0.get(&(species, body_type)) {
5807            Some(spec) => spec,
5808            None => {
5809                error!(
5810                    "No right upper head specification exists for the combination of {:?} and {:?}",
5811                    species, body_type
5812                );
5813                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5814            },
5815        };
5816
5817        let latspec = &spec.right_upper.lateral;
5818        let lateral =
5819            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.right_upper.model_index);
5820
5821        (lateral, Vec3::from(spec.right_upper.offset))
5822    }
5823
5824    fn mesh_right_head_lower(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5825        let spec = match self.0.get(&(species, body_type)) {
5826            Some(spec) => spec,
5827            None => {
5828                error!(
5829                    "No right lower head specification exists for the combination of {:?} and {:?}",
5830                    species, body_type
5831                );
5832                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5833            },
5834        };
5835
5836        let latspec = &spec.right_lower.lateral;
5837        let lateral =
5838            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.right_lower.model_index);
5839
5840        (lateral, Vec3::from(spec.right_lower.offset))
5841    }
5842
5843    fn mesh_right_jaw(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5844        let spec = match self.0.get(&(species, body_type)) {
5845            Some(spec) => spec,
5846            None => {
5847                error!(
5848                    "No right jaw specification exists for the combination of {:?} and {:?}",
5849                    species, body_type
5850                );
5851                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5852            },
5853        };
5854
5855        let latspec = &spec.right_jaw.lateral;
5856        let lateral =
5857            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.right_jaw.model_index);
5858
5859        (lateral, Vec3::from(spec.right_jaw.offset))
5860    }
5861
5862    fn mesh_foot_fl(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5863        let spec = match self.0.get(&(species, body_type)) {
5864            Some(spec) => spec,
5865            None => {
5866                error!(
5867                    "No foot specification exists for the combination of {:?} and {:?}",
5868                    species, body_type
5869                );
5870                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5871            },
5872        };
5873        let latspec = &spec.front_left.lateral;
5874        let lateral =
5875            graceful_load_segment_flipped(&latspec.0, !latspec.1, spec.front_left.model_index);
5876
5877        (lateral, Vec3::from(spec.front_left.offset))
5878    }
5879
5880    fn mesh_foot_fr(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5881        let spec = match self.0.get(&(species, body_type)) {
5882            Some(spec) => spec,
5883            None => {
5884                error!(
5885                    "No foot specification exists for the combination of {:?} and {:?}",
5886                    species, body_type
5887                );
5888                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5889            },
5890        };
5891        let latspec = &spec.front_right.lateral;
5892        let lateral =
5893            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.front_right.model_index);
5894
5895        (lateral, Vec3::from(spec.front_right.offset))
5896    }
5897
5898    fn mesh_foot_bl(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5899        let spec = match self.0.get(&(species, body_type)) {
5900            Some(spec) => spec,
5901            None => {
5902                error!(
5903                    "No foot specification exists for the combination of {:?} and {:?}",
5904                    species, body_type
5905                );
5906                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5907            },
5908        };
5909        let latspec = &spec.back_left.lateral;
5910        let lateral =
5911            graceful_load_segment_flipped(&latspec.0, !latspec.1, spec.back_left.model_index);
5912
5913        (lateral, Vec3::from(spec.back_left.offset))
5914    }
5915
5916    fn mesh_foot_br(&self, species: QLSpecies, body_type: QLBodyType) -> BoneMeshes {
5917        let spec = match self.0.get(&(species, body_type)) {
5918            Some(spec) => spec,
5919            None => {
5920                error!(
5921                    "No foot specification exists for the combination of {:?} and {:?}",
5922                    species, body_type
5923                );
5924                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5925            },
5926        };
5927        let latspec = &spec.back_right.lateral;
5928        let lateral =
5929            graceful_load_segment_flipped(&latspec.0, latspec.1, spec.back_right.model_index);
5930
5931        (lateral, Vec3::from(spec.back_right.offset))
5932    }
5933}
5934
5935//////
5936#[derive(Deserialize)]
5937struct ObjectCentralSpec(HashMap<object::Body, SidedObjectCentralVoxSpec>);
5938
5939#[derive(Deserialize, Default)]
5940#[serde(default)]
5941struct SidedObjectCentralVoxSpec {
5942    bone0: ObjectCentralSubSpec,
5943    bone1: ObjectCentralSubSpec,
5944}
5945
5946#[derive(Deserialize, Default)]
5947struct ObjectCentralSubSpec {
5948    offset: [f32; 3], // Should be relative to initial origin
5949    central: VoxSimple,
5950    #[serde(default)]
5951    model_index: u32,
5952}
5953
5954make_vox_spec!(
5955    object::Body,
5956    struct ObjectSpec {
5957        central: ObjectCentralSpec = "voxygen.voxel.object_manifest",
5958    },
5959    |FigureKey { body, .. }, spec| {
5960        [
5961            Some(spec.central.read().0.mesh_bone0(body)),
5962            Some(spec.central.read().0.mesh_bone1(body)),
5963            None,
5964            None,
5965            None,
5966            None,
5967            None,
5968            None,
5969            None,
5970            None,
5971            None,
5972            None,
5973            None,
5974            None,
5975            None,
5976            None,
5977        ]
5978    },
5979);
5980
5981impl ObjectCentralSpec {
5982    fn mesh_bone0(&self, obj: &object::Body) -> BoneMeshes {
5983        let spec = match self.0.get(obj) {
5984            Some(spec) => spec,
5985            None => {
5986                error!("No specification exists for {:?}", obj);
5987                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
5988            },
5989        };
5990        let central = graceful_load_segment(&spec.bone0.central.0, spec.bone0.model_index);
5991
5992        (central, Vec3::from(spec.bone0.offset))
5993    }
5994
5995    fn mesh_bone1(&self, obj: &object::Body) -> BoneMeshes {
5996        let spec = match self.0.get(obj) {
5997            Some(spec) => spec,
5998            None => {
5999                error!("No specification exists for {:?}", obj);
6000                return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
6001            },
6002        };
6003        let central = graceful_load_segment(&spec.bone1.central.0, spec.bone1.model_index);
6004
6005        (central, Vec3::from(spec.bone1.offset))
6006    }
6007}
6008impl_concatenate_for_wrapper!(ObjectCentralSpec);
6009
6010struct ModelWithOptionalIndex(String, u32);
6011
6012impl<'de> Deserialize<'de> for ModelWithOptionalIndex {
6013    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
6014        struct StringWithOptionalIndex;
6015        use serde::de;
6016
6017        impl<'de> de::Visitor<'de> for StringWithOptionalIndex {
6018            type Value = ModelWithOptionalIndex;
6019
6020            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
6021                formatter.write_str("model_spec or (spec, index)")
6022            }
6023
6024            fn visit_str<E: de::Error>(self, model: &str) -> Result<Self::Value, E> {
6025                Ok(ModelWithOptionalIndex(model.into(), DEFAULT_INDEX))
6026            }
6027
6028            fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
6029                if let Some(spec) = seq.next_element::<String>()? {
6030                    if let Some(num) = seq.next_element::<u32>()? {
6031                        Ok(ModelWithOptionalIndex(spec, num))
6032                    } else {
6033                        Err(de::Error::missing_field("index"))
6034                    }
6035                } else {
6036                    Err(de::Error::missing_field("spec"))
6037                }
6038            }
6039        }
6040        deserializer.deserialize_any(StringWithOptionalIndex {})
6041    }
6042}
6043
6044#[derive(Deserialize)]
6045struct ItemCentralSpec(HashMap<ItemKey, ModelWithOptionalIndex>);
6046impl_concatenate_for_wrapper!(ItemCentralSpec);
6047
6048make_vox_spec!(
6049    body::item::Body,
6050    struct ItemSpec {
6051        central: ItemCentralSpec = "voxygen.voxel.item_drop_manifest",
6052    },
6053    |FigureKey { body, item_key, .. }, spec| {
6054        [
6055            Some(
6056                spec.central
6057                    .read()
6058                    .0
6059                    .mesh_bone0(body, item_key.as_deref().unwrap_or(&ItemKey::Empty)),
6060            ),
6061            None,
6062            None,
6063            None,
6064            None,
6065            None,
6066            None,
6067            None,
6068            None,
6069            None,
6070            None,
6071            None,
6072            None,
6073            None,
6074            None,
6075            None,
6076        ]
6077    },
6078);
6079
6080impl ItemCentralSpec {
6081    fn mesh_bone0(&self, item: &body::item::Body, item_key: &ItemKey) -> BoneMeshes {
6082        let coin_pouch = ModelWithOptionalIndex("voxel.object.pouch".to_string(), DEFAULT_INDEX);
6083
6084        if let Some(spec) = match item {
6085            body::item::Body::CoinPouch => Some(&coin_pouch),
6086            _ => self.0.get(item_key),
6087        } {
6088            let full_spec: String = ["voxygen.", spec.0.as_str()].concat();
6089            let segment = match item {
6090                body::item::Body::Armor(_) => MatSegment::from_vox_model_index(
6091                    &graceful_load_vox_fullspec(&full_spec).read().0,
6092                    spec.1 as usize,
6093                )
6094                .map(|mat_cell| match mat_cell {
6095                    MatCell::None => None,
6096                    MatCell::Mat(_) => Some(MatCell::None),
6097                    MatCell::Normal(data) => data.is_hollow().then_some(MatCell::None),
6098                })
6099                .to_segment(|_| Default::default()),
6100                _ => graceful_load_segment_fullspec(&full_spec, spec.1),
6101            };
6102            let offset = segment_center(&segment).unwrap_or_default();
6103            (segment, match item {
6104                // TODO: apply non-random rotations to items here
6105                body::item::Body::Tool(_) | body::item::Body::Thrown(_) => {
6106                    Vec3::new(offset.x - 2.0, offset.y, offset.z)
6107                },
6108                body::item::Body::Armor(
6109                    body::item::ItemArmorKind::Neck
6110                    | body::item::ItemArmorKind::Back
6111                    | body::item::ItemArmorKind::Tabard,
6112                ) => Vec3::new(offset.x, offset.y - 2.0, offset.z),
6113                _ => offset * Vec3::new(1.0, 1.0, 0.0),
6114            })
6115        } else {
6116            error!("No specification exists for {:?}, {:?}", item, item_key);
6117            load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5))
6118        }
6119    }
6120}
6121
6122fn segment_center(segment: &Segment) -> Option<Vec3<f32>> {
6123    let (mut x_min, mut x_max, mut y_min, mut y_max, mut z_min, mut z_max) =
6124        (i32::MAX, 0, i32::MAX, 0, i32::MAX, 0);
6125    for pos in segment.full_pos_iter() {
6126        if let Ok(Cell::Filled(data)) = segment.get(pos) {
6127            if !data.is_hollow() {
6128                if pos.x < x_min {
6129                    x_min = pos.x;
6130                } else if pos.x > x_max {
6131                    x_max = pos.x;
6132                }
6133                if pos.y < y_min {
6134                    y_min = pos.y;
6135                } else if pos.y > y_max {
6136                    y_max = pos.y;
6137                }
6138                if pos.z < z_min {
6139                    z_min = pos.z;
6140                } else if pos.z > z_max {
6141                    z_max = pos.z;
6142                }
6143            }
6144        }
6145    }
6146
6147    if (x_min, x_max, y_min, y_max, z_min, z_max) == (i32::MAX, 0, i32::MAX, 0, i32::MAX, 0) {
6148        None
6149    } else {
6150        Some(Vec3::new(x_min + x_max, y_min + y_max, z_min + z_max).map(|n| n as f32 / -2.0))
6151    }
6152}
6153
6154pub type ShipBoneMeshes = (Dyna<Block, ()>, Vec3<f32>);
6155
6156fn mesh_ship_bone<'a, K: fmt::Debug + Eq + Hash, V, F: Fn(&V) -> Option<&'a VoxelCollider>>(
6157    map: &HashMap<K, V>,
6158    obj: &K,
6159    f: F,
6160) -> Option<ShipBoneMeshes> {
6161    let spec = match map.get(obj) {
6162        Some(spec) => spec,
6163        None => {
6164            error!("No specification exists for {:?}", obj);
6165
6166            return None;
6167        },
6168    };
6169    let bone = f(spec);
6170
6171    bone.map(|bone| (bone.volume().clone(), bone.translation))
6172}
6173
6174impl BodySpec for ship::Body {
6175    type BoneMesh = ShipBoneMeshes;
6176    type Extra = ();
6177    type Manifests = AssetHandle<Self::Spec>;
6178    type ModelEntryFuture<const N: usize> = TerrainModelEntryFuture<N>;
6179    type Spec = ShipSpec;
6180
6181    fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
6182
6183    fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() }
6184
6185    fn bone_meshes(
6186        FigureKey { body, .. }: &FigureKey<Self>,
6187        manifests: &Self::Manifests,
6188        _: Self::Extra,
6189    ) -> [Option<Self::BoneMesh>; anim::MAX_BONE_COUNT] {
6190        let spec = manifests.read();
6191        let spec = &*spec;
6192        let map = &spec.central.read().0.0;
6193        [
6194            mesh_ship_bone(map, body, |ship| spec.colliders.get(&ship.bone0.central.0)),
6195            mesh_ship_bone(map, body, |ship| spec.colliders.get(&ship.bone1.central.0)),
6196            mesh_ship_bone(map, body, |ship| spec.colliders.get(&ship.bone2.central.0)),
6197            mesh_ship_bone(map, body, |ship| spec.colliders.get(&ship.bone3.central.0)),
6198            None,
6199            None,
6200            None,
6201            None,
6202            None,
6203            None,
6204            None,
6205            None,
6206            None,
6207            None,
6208            None,
6209            None,
6210        ]
6211    }
6212}
6213
6214#[cfg(feature = "plugins")]
6215mod plugin {
6216    use super::assets;
6217    use common_assets::{AssetExt, AssetHandle, Concatenate, MultiRon};
6218    use hashbrown::HashMap;
6219    use serde::Deserialize;
6220
6221    #[derive(Debug, Deserialize, Default, Clone, Copy)]
6222    pub enum Orientation {
6223        #[default]
6224        Normal,
6225        Mirror,
6226    }
6227
6228    #[derive(Debug, Deserialize, Clone)]
6229    pub struct BoneMesh {
6230        pub model: String,
6231        pub offset: [f32; 3],
6232        #[serde(default)]
6233        pub model_index: u16,
6234        #[serde(default)]
6235        pub transform: Orientation,
6236    }
6237
6238    #[derive(Deserialize, Clone)]
6239    pub struct PluginBoneSpec(pub(super) HashMap<String, Vec<BoneMesh>>);
6240
6241    impl assets::Compound for PluginBoneSpec {
6242        fn load(
6243            _cache: assets::AnyCache,
6244            _: &assets::SharedString,
6245        ) -> Result<Self, assets::BoxedError> {
6246            let data: AssetHandle<MultiRon<PluginBoneSpec>> =
6247                AssetExt::load("voxygen.voxel.plugin_body_manifest")?;
6248            Ok(data.read().0.clone())
6249        }
6250    }
6251
6252    impl_concatenate_for_wrapper!(PluginBoneSpec);
6253}
6254
6255#[cfg(feature = "plugins")]
6256impl BodySpec for common::comp::plugin::Body {
6257    type BoneMesh = BoneMeshes;
6258    type Extra = ();
6259    type Manifests = AssetHandle<Self::Spec>;
6260    type ModelEntryFuture<const N: usize> = FigureModelEntryFuture<N>;
6261    type Spec = plugin::PluginBoneSpec;
6262
6263    fn load_spec() -> Result<Self::Manifests, assets::Error> { Self::Spec::load("") }
6264
6265    fn reload_watcher(manifests: &Self::Manifests) -> ReloadWatcher { manifests.reload_watcher() }
6266
6267    fn bone_meshes(
6268        key: &FigureKey<Self>,
6269        manifests: &Self::Manifests,
6270        _extra: Self::Extra,
6271    ) -> [Option<BoneMeshes>; anim::MAX_BONE_COUNT] {
6272        let mut result = std::array::from_fn(|_| None);
6273        if let Some(bones) = manifests.read().0.get(&key.body.id()) {
6274            for (mesh, result) in bones.iter().zip(result.iter_mut()) {
6275                *result = Some((
6276                    graceful_load_segment_flipped(
6277                        &mesh.model,
6278                        matches!(mesh.transform, plugin::Orientation::Mirror),
6279                        mesh.model_index.into(),
6280                    ),
6281                    mesh.offset.into(),
6282                ));
6283            }
6284        }
6285        result
6286    }
6287}