veloren_voxygen/scene/figure/
load.rs

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