veloren_voxygen/scene/figure/
load.rs

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