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