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