From 95b6d5e8034ba7362b565653be5d195a491ad4e9 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Mon, 31 Aug 2020 03:01:20 +0200 Subject: [PATCH] Further generalize the typed module. This enables us to automatically create configuration formats from enums or structs. For enums, we create a structure with a field for each case, representing a pattern match; the configuration format can then enter a different expression for each case. For structs, we create an enum with a variant for each field, representing projecting by that field; the configuration format selects the field to project from, and then can write a further expression on that field (for instance, it can perform another pattern match). So far we don't actually have anything that *uses* this functionality; I decided to finish it for the purpose of specifying a default lantern offset, only to discover that we already return a lantern offset from the animation crate. So I fixed it there instead. --- common/src/comp/body/biped_large.rs | 50 +++-- common/src/comp/body/bird_medium.rs | 56 +++-- common/src/comp/body/bird_small.rs | 71 +++--- common/src/comp/body/critter.rs | 53 +++-- common/src/comp/body/dragon.rs | 43 ++-- common/src/comp/body/fish_medium.rs | 102 +++++---- common/src/comp/body/fish_small.rs | 43 ++-- common/src/comp/body/golem.rs | 43 ++-- common/src/comp/body/humanoid.rs | 36 +-- common/src/comp/body/object.rs | 132 +++++------ common/src/comp/body/quadruped_low.rs | 58 +++-- common/src/comp/body/quadruped_medium.rs | 63 +++--- common/src/comp/body/quadruped_small.rs | 73 ++++--- common/src/typed.rs | 266 ++++++++++++++++++++--- voxygen/src/anim/src/object/mod.rs | 4 +- voxygen/src/scene/figure/mod.rs | 9 +- 16 files changed, 729 insertions(+), 373 deletions(-) diff --git a/common/src/comp/body/biped_large.rs b/common/src/comp/body/biped_large.rs index d8ba2a9f95..9e007caee9 100644 --- a/common/src/comp/body/biped_large.rs +++ b/common/src/comp/body/biped_large.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,15 +29,18 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::BipedLarge(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Ogre = 0, - Cyclops = 1, - Wendigo = 2, - Troll = 3, - Dullahan = 4, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Ogre = 0, + Cyclops = 1, + Wendigo = 2, + Troll = 3, + Dullahan = 4, + } +); /// Data representing per-species generic data. /// @@ -77,10 +84,13 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/bird_medium.rs b/common/src/comp/body/bird_medium.rs index 80522daf1e..26e7e7fa5c 100644 --- a/common/src/comp/body/bird_medium.rs +++ b/common/src/comp/body/bird_medium.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,18 +29,21 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::BirdMedium(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Duck = 0, - Chicken = 1, - Goose = 2, - Peacock = 3, - Eagle = 4, - Snowyowl = 5, - Parrot = 6, - Cockatrice = 7, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Duck = 0, + Chicken = 1, + Goose = 2, + Peacock = 3, + Eagle = 4, + Snowyowl = 5, + Parrot = 6, + Cockatrice = 7, + } +); /// Data representing per-species generic data. /// @@ -89,10 +96,13 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/bird_small.rs b/common/src/comp/body/bird_small.rs index 8441f41b8f..a3be8c3087 100644 --- a/common/src/comp/body/bird_small.rs +++ b/common/src/comp/body/bird_small.rs @@ -1,13 +1,18 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub head: Head, - pub torso: Torso, - pub wing_l: WingL, - pub wing_r: WingR, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub head: Head, + pub torso: Torso, + pub wing_l: WingL, + pub wing_r: WingR, + } +); + impl Body { pub fn random() -> Self { let mut rng = thread_rng(); @@ -20,30 +25,42 @@ impl Body { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Head { - Default, -} +make_case_elim!( + head, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Head { + Default = 0, + } +); const ALL_HEADS: [Head; 1] = [Head::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Torso { - Default, -} +make_case_elim!( + torso, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Torso { + Default = 0, + } +); const ALL_TORSOS: [Torso; 1] = [Torso::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingL { - Default, -} +make_case_elim!( + wing_l, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum WingL { + Default = 0, + } +); const ALL_WING_LS: [WingL; 1] = [WingL::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingR { - Default, -} +make_case_elim!( + wing_r, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum WingR { + Default = 0, + } +); const ALL_WING_RS: [WingR; 1] = [WingR::Default]; diff --git a/common/src/comp/body/critter.rs b/common/src/comp/body/critter.rs index 0c67b0218f..c3d0115693 100644 --- a/common/src/comp/body/critter.rs +++ b/common/src/comp/body/critter.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,16 +29,19 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::Critter(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Rat = 0, - Axolotl = 1, - Gecko = 2, - Turtle = 3, - Squirrel = 4, - Fungome = 5, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Rat = 0, + Axolotl = 1, + Gecko = 2, + Turtle = 3, + Squirrel = 4, + Fungome = 5, + } +); /// Data representing per-species generic data. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -79,10 +86,14 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); + pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/dragon.rs b/common/src/comp/body/dragon.rs index d4dae25a7d..07c3991a44 100644 --- a/common/src/comp/body/dragon.rs +++ b/common/src/comp/body/dragon.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,11 +29,14 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::Dragon(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Reddragon = 0, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Reddragon = 0, + } +); /// Data representing per-species generic data. /// @@ -59,10 +66,14 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); + pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/fish_medium.rs b/common/src/comp/body/fish_medium.rs index a3c2ee931e..e1fe43cb74 100644 --- a/common/src/comp/body/fish_medium.rs +++ b/common/src/comp/body/fish_medium.rs @@ -1,15 +1,20 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub head: Head, - pub torso: Torso, - pub rear: Rear, - pub tail: Tail, - pub fin_l: FinL, - pub fin_r: FinR, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub head: Head, + pub torso: Torso, + pub rear: Rear, + pub tail: Tail, + pub fin_l: FinL, + pub fin_r: FinR, + } +); + impl Body { pub fn random() -> Self { let mut rng = thread_rng(); @@ -24,44 +29,63 @@ impl Body { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Head { - Default, -} +make_case_elim!( + head, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Head { + Default = 0, + } +); + const ALL_HEADS: [Head; 1] = [Head::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Torso { - Default, -} +make_case_elim!( + torso, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Torso { + Default = 0, + } +); const ALL_TORSOS: [Torso; 1] = [Torso::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Rear { - Default, -} +make_case_elim!( + rear, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Rear { + Default = 0, + } +); const ALL_REARS: [Rear; 1] = [Rear::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Tail { - Default, -} +make_case_elim!( + tail, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Tail { + Default = 0, + } +); const ALL_TAILS: [Tail; 1] = [Tail::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FinL { - Default, -} +make_case_elim!( + fin_l, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum FinL { + Default = 0, + } +); const ALL_FIN_LS: [FinL; 1] = [FinL::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FinR { - Default, -} +make_case_elim!( + fin_r, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum FinR { + Default = 0, + } +); const ALL_FIN_RS: [FinR; 1] = [FinR::Default]; diff --git a/common/src/comp/body/fish_small.rs b/common/src/comp/body/fish_small.rs index 6a2a46786a..31753df95d 100644 --- a/common/src/comp/body/fish_small.rs +++ b/common/src/comp/body/fish_small.rs @@ -1,11 +1,16 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub torso: Torso, - pub tail: Tail, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub torso: Torso, + pub tail: Tail, + } +); + impl Body { pub fn random() -> Self { let mut rng = thread_rng(); @@ -16,16 +21,24 @@ impl Body { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Torso { - Default, -} +make_case_elim!( + torso, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Torso { + Default = 0, + } +); + const ALL_TORSOS: [Torso; 1] = [Torso::Default]; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Tail { - Default, -} +make_case_elim!( + tail, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Tail { + Default = 0, + } +); + const ALL_TAILS: [Tail; 1] = [Tail::Default]; diff --git a/common/src/comp/body/golem.rs b/common/src/comp/body/golem.rs index 455007f169..2e2af8c22a 100644 --- a/common/src/comp/body/golem.rs +++ b/common/src/comp/body/golem.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,11 +29,14 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::Golem(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - StoneGolem = 0, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + StoneGolem = 0, + } +); /// Data representing per-species generic data. /// @@ -59,10 +66,14 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); + pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/humanoid.rs b/common/src/comp/body/humanoid.rs index 59873b44f7..43a3d0dc1f 100644 --- a/common/src/comp/body/humanoid.rs +++ b/common/src/comp/body/humanoid.rs @@ -1,20 +1,30 @@ -use crate::make_case_elim; +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng, Rng}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, - pub hair_style: u8, - pub beard: u8, - pub eyes: u8, - pub accessory: u8, - pub hair_color: u8, - pub skin: u8, - pub eye_color: u8, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + #[typed(pure)] + pub hair_style: u8, + #[typed(pure)] + pub beard: u8, + #[typed(pure)] + pub eyes: u8, + #[typed(pure)] + pub accessory: u8, + #[typed(pure)] + pub hair_color: u8, + #[typed(pure)] + pub skin: u8, + #[typed(pure)] + pub eye_color: u8, + } +); impl Body { pub fn random() -> Self { diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs index e94d21a93d..474a22380f 100644 --- a/common/src/comp/body/object.rs +++ b/common/src/comp/body/object.rs @@ -1,70 +1,74 @@ +use crate::make_case_elim; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Body { - Arrow = 0, - Bomb = 1, - Scarecrow = 2, - Cauldron = 3, - ChestVines = 4, - Chest = 5, - ChestDark = 6, - ChestDemon = 7, - ChestGold = 8, - ChestLight = 9, - ChestOpen = 10, - ChestSkull = 11, - Pumpkin = 12, - Pumpkin2 = 13, - Pumpkin3 = 14, - Pumpkin4 = 15, - Pumpkin5 = 16, - Campfire = 17, - LanternGround = 18, - LanternGroundOpen = 19, - LanternStanding2 = 20, - LanternStanding = 21, - PotionBlue = 22, - PotionGreen = 23, - PotionRed = 24, - Crate = 25, - Tent = 26, - WindowSpooky = 27, - DoorSpooky = 28, - Anvil = 29, - Gravestone = 30, - Gravestone2 = 31, - Bench = 32, - Chair = 33, - Chair2 = 34, - Chair3 = 35, - Table = 36, - Table2 = 37, - Table3 = 38, - Drawer = 39, - BedBlue = 40, - Carpet = 41, - Bedroll = 42, - CarpetHumanRound = 43, - CarpetHumanSquare = 44, - CarpetHumanSquare2 = 45, - CarpetHumanSquircle = 46, - Pouch = 47, - CraftingBench = 48, - BoltFire = 49, - ArrowSnake = 50, - CampfireLit = 51, - BoltFireBig = 52, - TrainingDummy = 53, - FireworkBlue = 54, - FireworkGreen = 55, - FireworkPurple = 56, - FireworkRed = 57, - FireworkYellow = 58, - MultiArrow = 59, -} +make_case_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Body { + Arrow = 0, + Bomb = 1, + Scarecrow = 2, + Cauldron = 3, + ChestVines = 4, + Chest = 5, + ChestDark = 6, + ChestDemon = 7, + ChestGold = 8, + ChestLight = 9, + ChestOpen = 10, + ChestSkull = 11, + Pumpkin = 12, + Pumpkin2 = 13, + Pumpkin3 = 14, + Pumpkin4 = 15, + Pumpkin5 = 16, + Campfire = 17, + LanternGround = 18, + LanternGroundOpen = 19, + LanternStanding2 = 20, + LanternStanding = 21, + PotionBlue = 22, + PotionGreen = 23, + PotionRed = 24, + Crate = 25, + Tent = 26, + WindowSpooky = 27, + DoorSpooky = 28, + Anvil = 29, + Gravestone = 30, + Gravestone2 = 31, + Bench = 32, + Chair = 33, + Chair2 = 34, + Chair3 = 35, + Table = 36, + Table2 = 37, + Table3 = 38, + Drawer = 39, + BedBlue = 40, + Carpet = 41, + Bedroll = 42, + CarpetHumanRound = 43, + CarpetHumanSquare = 44, + CarpetHumanSquare2 = 45, + CarpetHumanSquircle = 46, + Pouch = 47, + CraftingBench = 48, + BoltFire = 49, + ArrowSnake = 50, + CampfireLit = 51, + BoltFireBig = 52, + TrainingDummy = 53, + FireworkBlue = 54, + FireworkGreen = 55, + FireworkPurple = 56, + FireworkRed = 57, + FireworkYellow = 58, + MultiArrow = 59, + } +); impl Body { pub fn random() -> Self { diff --git a/common/src/comp/body/quadruped_low.rs b/common/src/comp/body/quadruped_low.rs index ceac93e830..16aee7611c 100644 --- a/common/src/comp/body/quadruped_low.rs +++ b/common/src/comp/body/quadruped_low.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,19 +29,22 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::QuadrupedLow(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Crocodile = 0, - Alligator = 1, - Salamander = 2, - Monitor = 3, - Asp = 4, - Tortoise = 5, - Rocksnapper = 6, - Pangolin = 7, - Maneater = 8, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Crocodile = 0, + Alligator = 1, + Salamander = 2, + Monitor = 3, + Asp = 4, + Tortoise = 5, + Rocksnapper = 6, + Pangolin = 7, + Maneater = 8, + } +); /// Data representing per-species generic data. /// @@ -93,10 +100,13 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/quadruped_medium.rs b/common/src/comp/body/quadruped_medium.rs index 4c1a70106e..191c36fb02 100644 --- a/common/src/comp/body/quadruped_medium.rs +++ b/common/src/comp/body/quadruped_medium.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,21 +29,24 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::QuadrupedMedium(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Grolgar = 0, - Saber = 1, - Tiger = 2, - Tuskram = 3, - Lion = 6, - Tarasque = 7, - Wolf = 8, - Frostfang = 9, - Mouflon = 10, - Catoblepas = 11, - Bonerattler = 12, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Grolgar = 0, + Saber = 1, + Tiger = 2, + Tuskram = 3, + Lion = 6, + Tarasque = 7, + Wolf = 8, + Frostfang = 9, + Mouflon = 10, + Catoblepas = 11, + Bonerattler = 12, + } +); /// Data representing per-species generic data. /// @@ -101,10 +108,14 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); + pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/body/quadruped_small.rs b/common/src/comp/body/quadruped_small.rs index 63055e856a..b0829352f6 100644 --- a/common/src/comp/body/quadruped_small.rs +++ b/common/src/comp/body/quadruped_small.rs @@ -1,11 +1,15 @@ +use crate::{make_case_elim, make_proj_elim}; use rand::{seq::SliceRandom, thread_rng}; use serde::{Deserialize, Serialize}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Body { - pub species: Species, - pub body_type: BodyType, -} +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); impl Body { pub fn random() -> Self { @@ -25,26 +29,29 @@ impl From for super::Body { fn from(body: Body) -> Self { super::Body::QuadrupedSmall(body) } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Species { - Pig = 0, - Fox = 1, - Sheep = 2, - Boar = 3, - Jackalope = 4, - Skunk = 5, - Cat = 6, - Batfox = 7, - Raccoon = 8, - Quokka = 9, - Dodarock = 10, - Holladon = 11, - Hyena = 12, - Rabbit = 13, - Truffler = 14, - Frog = 15, -} +make_case_elim!( + species, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum Species { + Pig = 0, + Fox = 1, + Sheep = 2, + Boar = 3, + Jackalope = 4, + Skunk = 5, + Cat = 6, + Batfox = 7, + Raccoon = 8, + Quokka = 9, + Dodarock = 10, + Holladon = 11, + Hyena = 12, + Rabbit = 13, + Truffler = 14, + Frog = 15, + } +); /// Data representing per-species generic data. /// @@ -121,10 +128,14 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum BodyType { - Female = 0, - Male = 1, -} +make_case_elim!( + body_type, + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); + pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/typed.rs b/common/src/typed.rs index 671ab2e565..e3613363f4 100644 --- a/common/src/typed.rs +++ b/common/src/typed.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; +use serde::{Deserialize, Serialize}; pub trait SubContext { fn sub_context(self) -> Context; @@ -16,10 +17,52 @@ pub trait Typed { fn reduce(self, context: Context) -> (Type, S); } +/// Given a head expression (Self) and a target type (Type), +/// attempt to synthesize a term that reduces head into the target type. +/// +/// How we do this depends on the type of the head expression: +/// +/// - For enums, we synthesize a match on the current head. For each match arm, +/// we then repeat this process on the constructor arguments; if there are no +/// constructor arguments, we synthesize a literal (Pure term). (TODO: Handle +/// > 1 tuple properly--for now we just synthesize a Pure term for these +/// cases). +/// +/// - For structs, we synthesize a projection on the current head. For each +/// projection, we then repeat this process on the type of the projected +/// field. +/// +/// - For other types (which currently have to opt out during the field +/// declaration), we synthesize a literal. +/// +/// TODO: Differentiate between the context and the stack at some point; for +/// now, we only use the context as a stack. +pub trait SynthTyped { + type Expr; +} + +/// Weak head reduction type (equivalent to applying a reduction to the head +/// variable, but this way we don't have to implement variable lookup and it +/// doesn't serialize with variables). +#[fundamental] +#[serde(transparent)] +#[derive(Deserialize, Serialize)] +pub struct WeakHead { + pub red: Reduction, + #[serde(skip)] + pub ty: PhantomData, +} + +#[serde(transparent)] +#[derive(Deserialize, Serialize)] pub struct Pure(pub T); -impl, T, S> Typed, S> for T { - fn reduce(self, context: Context) -> (Pure, S) { (Pure(self), context.sub_context()) } +impl<'a, Context: SubContext, T, S> Typed for &'a Pure { + fn reduce(self, context: Context) -> (&'a T, S) { (&self.0, context.sub_context()) } +} + +impl SynthTyped for WeakHead, Target> { + type Expr = Pure; } /// A lazy pattern match reified as a Rust type. @@ -50,7 +93,7 @@ impl, T, S> Typed, S> for T { /// #[derive(Clone,Copy)] /// pub enum MyType { /// Constr1 = 0, -/// Constr2(arg : u8) = 1, +/// #[typed(pure)] Constr2(arg : u8) = 1, /// /* ..., */ /// } /// ); @@ -141,18 +184,26 @@ impl, T, S> Typed, S> for T { /// /// Limitations: /// -/// Unfortunately, due to restrictions on procedural macros, we currently always +/// Unfortunately, due to restrictions on macro_rules, we currently always /// require the types defined to #[repr(inttype)] as you can see above. There /// are also some other current limitations that we hopefully will be able to /// lift at some point; struct variants are not yet supported, and neither /// attributes on fields. #[fundamental] -pub struct ElimCase { - pub expr: Expr, +#[serde(transparent)] +#[derive(Deserialize, Serialize)] +pub struct ElimCase { pub cases: Cases, - pub ty: PhantomData, } +#[fundamental] +#[serde(transparent)] +#[derive(Deserialize, Serialize)] +pub struct ElimProj { + pub proj: Proj, +} +pub type ElimWeak = as SynthTyped<((Type,), ()), Elim>>::Expr; + #[macro_export] macro_rules! as_item { ($i:item) => { @@ -160,10 +211,33 @@ macro_rules! as_item { }; } +#[macro_export] +/// This macro is used internally by typed. +/// +/// We use this in order to reliably construct a "representative" type for the +/// weak head reduction type. We need this because for some types of arguments +/// (empty variants for an enum, fields or constructor arguments explicitly +/// marked as #[typed(pure)], etc.) won't directly implement the WeakHead trait; +/// in such cases, we just synthesize a literal of the appropriate type. +macro_rules! make_weak_head_type { + ($Target:ty, $( #[$attr:meta] )* , ) => { + $crate::typed::Pure<$Target> + }; + ($Target:ty, #[ typed(pure) ] , $( $extra:tt )*) => { + $crate::typed::Pure<$Target> + }; + ($Target:ty, , $Type:ty, $( $extra:tt )*) => { + $crate::typed::Pure<$Target> + }; + ($Target:ty, , $Type:ty) => { + $Type + } +} + #[macro_export] macro_rules! make_case_elim { - ($mod:ident, $( #[$ty_attr:meta] )* $vis:vis enum $ty:ident { - $( $constr:ident $( ( $( $arg_name:ident : $arg_ty:ty ),* ) )? = $index:expr ),* $(,)? + ($mod:ident, $( #[ $ty_attr:meta ] )* $vis:vis enum $ty:ident { + $( $( #[$( $constr_attr:tt )*] )* $constr:ident $( ( $( $arg_name:ident : $arg_ty:ty ),* ) )? = $index:expr ),* $(,)? }) => { $crate::as_item! { $( #[$ty_attr] )* @@ -190,26 +264,48 @@ macro_rules! make_case_elim { $( pub $constr : Elim::$constr, )* } - impl PackedElim for $crate::typed::Pure { - $( type $constr = T; )* - } + pub type PureCases = $crate::typed::ElimCase>>; + } - pub type PureCases = Cases<$crate::typed::Pure>; + impl $mod::PackedElim for $crate::typed::Pure { + $( type $constr = $crate::typed::Pure; )* + } + + #[allow(unused_parens)] + impl $mod::PackedElim for $crate::typed::WeakHead<$ty, Target> + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $( $( $arg_ty ),* )?), Target> : + $crate::typed::SynthTyped<($( ($( $arg_ty, )*), )? ()), Target>, + )* + { + $( type $constr = + <$crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $( $( $arg_ty ),* )?), Target> + as $crate::typed::SynthTyped<($( ($( $arg_ty, )*), )? ()), Target>>::Expr; + )* + } + + #[allow(unused_parens)] + impl $crate::typed::SynthTyped<(($ty,), Context), Target> for $crate::typed::WeakHead<$ty, Target> + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $( $( $arg_ty ),* )?), Target> : + $crate::typed::SynthTyped<($( ($( $arg_ty, )*), )? ()), Target>, + )* + { + type Expr = $crate::typed::ElimCase<$mod::Cases<$crate::typed::WeakHead<$ty, Target>>>; } #[allow(unused_parens)] impl<'a, 'b, Elim: $mod::PackedElim, Context, Type, S> - $crate::typed::Typed for $crate::typed::ElimCase<&'a $ty, &'b $mod::Cases, Type> + $crate::typed::Typed<((&'a $ty,), Context), Type, S> for &'b $crate::typed::ElimCase<$mod::Cases> where - $( &'b Elim::$constr: $crate::typed::Typed<($( ($( &'a $arg_ty, )*), )? Context), Type, S>, )* + $( &'b Elim::$constr: $crate::typed::Typed<($( ($( &'a $arg_ty, )*), )? Context), Type, S> ),* { - fn reduce(self, context: Context) -> (Type, S) + fn reduce(self, ((head,), context): ((&'a $ty,), Context)) -> (Type, S) { - let Self { expr, cases, .. } = self; - match expr { + match head { $( $ty::$constr $( ($( $arg_name, )*) )? => <_ as $crate::typed::Typed<_, Type, _>>::reduce( - &cases.$constr, + &self.cases.$constr, ($( ($( $arg_name, )*), )? context), ), )* @@ -218,24 +314,132 @@ macro_rules! make_case_elim { } impl $ty { - pub fn elim_case<'a, 'b, Elim: $mod::PackedElim, Context, S, Type>(&'a self, cases: &'b $mod::Cases, context: Context) -> - (Type, S) + pub fn elim<'a, Elim, Context, S, Type>(&'a self, elim: Elim, context: Context) -> (Type, S) where - $crate::typed::ElimCase<&'a $ty, &'b $mod::Cases, Type> : $crate::typed::Typed, + Elim : $crate::typed::Typed<((&'a $ty,), Context), Type, S>, { - use $crate::typed::Typed; - - let case = $crate::typed::ElimCase { - expr: self, - cases, - ty: ::core::marker::PhantomData, - }; - case.reduce(context) + elim.reduce(((self,), context)) } pub fn elim_case_pure<'a, 'b, Type>(&'a self, cases: &'b $mod::PureCases) -> &'b Type { - let ($crate::typed::Pure(expr), ()) = self.elim_case(cases, ()); + let (expr, ()) = self.elim(cases, ()); + expr + } + + #[allow(unused_parens)] + pub fn elim_case_weak<'a, 'b, Type>(&'a self, cases: &'b $crate::typed::ElimWeak) -> &'b Type + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Type, $( #[$( $constr_attr )*] )* , $( $( $arg_ty ),* )?), Type> : + $crate::typed::SynthTyped<($( ($( $arg_ty, )*), )? ()), Type>, + )* + &'b $crate::typed::ElimWeak : $crate::typed::Typed<((&'a $ty,), ()), &'b Type, ()>, + { + let (expr, ()) = self.elim(cases, ()); + expr + } + } + } +} + +#[macro_export] +macro_rules! make_proj_elim { + ($mod:ident, $( #[ $ty_attr:meta ] )* $vis:vis struct $ty:ident { + $( $( #[$( $constr_attr:tt )*] )* $field_vis:vis $constr:ident : $arg_ty:ty ),* $(,)? + }) => { + $crate::as_item! { + $( #[$ty_attr] )* + $vis struct $ty { + $( $field_vis $constr : $arg_ty, )* + } + } + + #[allow(non_camel_case_types)] + #[allow(dead_code)] + $vis mod $mod { + use ::serde::{Deserialize, Serialize}; + + pub trait PackedElim { + $( type $constr; )* + } + + #[derive(Serialize, Deserialize)] + pub enum Proj { + $( $constr(Elim::$constr), )* + } + + pub type PureProj = $crate::typed::ElimProj>>; + } + + impl $mod::PackedElim for $crate::typed::Pure { + $( type $constr = $crate::typed::Pure; )* + } + + #[allow(unused_parens)] + impl $mod::PackedElim for $crate::typed::WeakHead<$ty, Target> + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $arg_ty), Target> : + $crate::typed::SynthTyped<(($arg_ty,), ()), Target>, + )* + { + $( type $constr = + <$crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $arg_ty), Target> + as $crate::typed::SynthTyped<(($arg_ty,), ()), Target>>::Expr; + )* + } + + #[allow(unused_parens)] + impl $crate::typed::SynthTyped<(($ty,), Context), Target> for $crate::typed::WeakHead<$ty, Target> + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Target, $( #[$( $constr_attr )*] )* , $arg_ty), Target> : + $crate::typed::SynthTyped<(($arg_ty,), ()), Target>, + )* + { + type Expr = $crate::typed::ElimProj<$mod::Proj<$crate::typed::WeakHead<$ty, Target>>>; + } + + #[allow(unused_parens)] + impl<'a, 'b, Elim: $mod::PackedElim, Context, Type, S> + $crate::typed::Typed<((&'a $ty,), Context), Type, S> for &'b $crate::typed::ElimProj<$mod::Proj> + where + $( &'b Elim::$constr: $crate::typed::Typed<((&'a $arg_ty,), Context), Type, S> ),* + { + fn reduce(self, ((head,), context): ((&'a $ty,), Context)) -> (Type, S) + { + match self.proj { + $( $mod::Proj::$constr(ref projection) => + <_ as $crate::typed::Typed<_, Type, _>>::reduce( + projection, + ((&head.$constr,), context), + ), + )* + } + } + } + + impl $ty { + pub fn elim<'a, Elim, Context, S, Type>(&'a self, elim: Elim, context: Context) -> (Type, S) + where + Elim : $crate::typed::Typed<((&'a $ty,), Context), Type, S>, + { + elim.reduce(((self,), context)) + } + + pub fn elim_proj_pure<'a, 'b, Type>(&'a self, cases: &'b $mod::PureProj) -> &'b Type + { + let (expr, ()) = self.elim(cases, ()); + expr + } + + #[allow(unused_parens)] + pub fn elim_proj_weak<'a, 'b, Type>(&'a self, cases: &'b $crate::typed::ElimWeak) -> &'b Type + where $( + $crate::typed::WeakHead<$crate::make_weak_head_type!(Type, $( #[$( $constr_attr )*] )* , $arg_ty), Type> : + $crate::typed::SynthTyped<(($arg_ty,), ()), Type>, + )* + &'b $crate::typed::ElimWeak : $crate::typed::Typed<((&'a $ty,), ()), &'b Type, ()>, + { + let (expr, ()) = self.elim(cases, ()); expr } } diff --git a/voxygen/src/anim/src/object/mod.rs b/voxygen/src/anim/src/object/mod.rs index 1c1306cba0..f7a0549663 100644 --- a/voxygen/src/anim/src/object/mod.rs +++ b/voxygen/src/anim/src/object/mod.rs @@ -35,7 +35,9 @@ impl Skeleton for ObjectSkeleton { buf: &mut [FigureBoneData; super::MAX_BONE_COUNT], ) -> Vec3 { buf[0] = make_bone(base_mat * Mat4::scaling_3d(SCALE)); - Vec3::default() + // TODO: Make dependent on bone, when we find an easier way to make that + // information available. + Vec3::unit_z() * 0.5 } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 25d033ac6e..e2b477f752 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -378,10 +378,10 @@ impl FigureMgr { } let dt = ecs.fetch::().0; let updater = ecs.read_resource::(); - for (entity, waypoint, light_emitter_opt, light_anim) in ( + for (entity, light_emitter_opt, body, light_anim) in ( &ecs.entities(), - ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), &mut ecs.write_storage::(), ) .join() @@ -401,10 +401,7 @@ impl FigureMgr { } else { (vek::Rgb::zero(), 0.0, 0.0, true) }; - if let Some(_) = waypoint { - light_anim.offset = vek::Vec3::unit_z() * 5.0; - } - if let Some(state) = self.states.character_states.get(&entity) { + if let Some(state) = body.and_then(|body| self.states.get_mut(body, &entity)) { light_anim.offset = vek::Vec3::from(state.lantern_offset); } if !light_anim.strength.is_normal() {