veloren_voxygen/scene/figure/
load.rs

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