Merge branch 'zesterer/cs-char-saving' into 'master'

Client-side character saving

See merge request veloren/veloren!737
This commit is contained in:
Joshua Barretto 2020-01-20 18:03:28 +00:00
commit 0223a60a1e
20 changed files with 455 additions and 206 deletions

View File

@ -29,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added a Death Screen and Hurt Screen - Added a Death Screen and Hurt Screen
- Added randomly selected Loading Screen background images - Added randomly selected Loading Screen background images
- Added options to disable clouds and to use cheaper water rendering - Added options to disable clouds and to use cheaper water rendering
- Added client-side character saving
### Changed ### Changed

1
Cargo.lock generated
View File

@ -3244,6 +3244,7 @@ name = "veloren-voxygen"
version = "0.4.0" version = "0.4.0"
dependencies = [ dependencies = [
"backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)",
"conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)",

View File

@ -13,17 +13,18 @@ use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage; use specs_idvs::IDVStorage;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Body { pub enum Body {
Humanoid(humanoid::Body), Humanoid(humanoid::Body) = 0,
QuadrupedSmall(quadruped_small::Body), QuadrupedSmall(quadruped_small::Body) = 1,
QuadrupedMedium(quadruped_medium::Body), QuadrupedMedium(quadruped_medium::Body) = 2,
BirdMedium(bird_medium::Body), BirdMedium(bird_medium::Body) = 3,
FishMedium(fish_medium::Body), FishMedium(fish_medium::Body) = 4,
Dragon(dragon::Body), Dragon(dragon::Body) = 5,
BirdSmall(bird_small::Body), BirdSmall(bird_small::Body) = 6,
FishSmall(fish_small::Body), FishSmall(fish_small::Body) = 7,
BipedLarge(biped_large::Body), BipedLarge(biped_large::Body) = 8,
Object(object::Body), Object(object::Body) = 9,
} }
impl Body { impl Body {

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub upper_torso: UpperTorso, pub upper_torso: UpperTorso,
@ -34,66 +35,77 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum UpperTorso { pub enum UpperTorso {
Default, Default,
} }
const ALL_UPPER_TORSOS: [UpperTorso; 1] = [UpperTorso::Default]; const ALL_UPPER_TORSOS: [UpperTorso; 1] = [UpperTorso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum LowerTorso { pub enum LowerTorso {
Default, Default,
} }
const ALL_LOWER_TORSOS: [LowerTorso; 1] = [LowerTorso::Default]; const ALL_LOWER_TORSOS: [LowerTorso; 1] = [LowerTorso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum ShoulderL { pub enum ShoulderL {
Default, Default,
} }
const ALL_SHOULDER_LS: [ShoulderL; 1] = [ShoulderL::Default]; const ALL_SHOULDER_LS: [ShoulderL; 1] = [ShoulderL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum ShoulderR { pub enum ShoulderR {
Default, Default,
} }
const ALL_SHOULDER_RS: [ShoulderR; 1] = [ShoulderR::Default]; const ALL_SHOULDER_RS: [ShoulderR; 1] = [ShoulderR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum HandL { pub enum HandL {
Default, Default,
} }
const ALL_HAND_LS: [HandL; 1] = [HandL::Default]; const ALL_HAND_LS: [HandL; 1] = [HandL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum HandR { pub enum HandR {
Default, Default,
} }
const ALL_HAND_RS: [HandR; 1] = [HandR::Default]; const ALL_HAND_RS: [HandR; 1] = [HandR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum LegL { pub enum LegL {
Default, Default,
} }
const ALL_LEG_LS: [LegL; 1] = [LegL::Default]; const ALL_LEG_LS: [LegL; 1] = [LegL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum LegR { pub enum LegR {
Default, Default,
} }
const ALL_LEG_RS: [LegR; 1] = [LegR::Default]; const ALL_LEG_RS: [LegR; 1] = [LegR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootL { pub enum FootL {
Default, Default,
} }
const ALL_FOOT_LS: [FootL; 1] = [FootL::Default]; const ALL_FOOT_LS: [FootL; 1] = [FootL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootR { pub enum FootR {
Default, Default,
} }

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub torso: Torso, pub torso: Torso,
@ -26,42 +27,49 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Torso { pub enum Torso {
Default, Default,
} }
const ALL_TORSOS: [Torso; 1] = [Torso::Default]; const ALL_TORSOS: [Torso; 1] = [Torso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Tail { pub enum Tail {
Default, Default,
} }
const ALL_TAILS: [Tail; 1] = [Tail::Default]; const ALL_TAILS: [Tail; 1] = [Tail::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingL { pub enum WingL {
Default, Default,
} }
const ALL_WING_LS: [WingL; 1] = [WingL::Default]; const ALL_WING_LS: [WingL; 1] = [WingL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingR { pub enum WingR {
Default, Default,
} }
const ALL_WING_RS: [WingR; 1] = [WingR::Default]; const ALL_WING_RS: [WingR; 1] = [WingR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum LegL { pub enum LegL {
Default, Default,
} }
const ALL_LEG_LS: [LegL; 1] = [LegL::Default]; const ALL_LEG_LS: [LegL; 1] = [LegL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum LegR { pub enum LegR {
Default, Default,
} }

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub torso: Torso, pub torso: Torso,
@ -20,24 +21,28 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Torso { pub enum Torso {
Default, Default,
} }
const ALL_TORSOS: [Torso; 1] = [Torso::Default]; const ALL_TORSOS: [Torso; 1] = [Torso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingL { pub enum WingL {
Default, Default,
} }
const ALL_WING_LS: [WingL; 1] = [WingL::Default]; const ALL_WING_LS: [WingL; 1] = [WingL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingR { pub enum WingR {
Default, Default,
} }

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub chest_front: ChestFront, pub chest_front: ChestFront,
@ -38,78 +39,91 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum ChestFront { pub enum ChestFront {
Default, Default,
} }
const ALL_CHEST_FRONTS: [ChestFront; 1] = [ChestFront::Default]; const ALL_CHEST_FRONTS: [ChestFront; 1] = [ChestFront::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum ChestRear { pub enum ChestRear {
Default, Default,
} }
const ALL_CHEST_REARS: [ChestRear; 1] = [ChestRear::Default]; const ALL_CHEST_REARS: [ChestRear; 1] = [ChestRear::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum TailFront { pub enum TailFront {
Default, Default,
} }
const ALL_TAIL_FRONTS: [TailFront; 1] = [TailFront::Default]; const ALL_TAIL_FRONTS: [TailFront; 1] = [TailFront::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum TailRear { pub enum TailRear {
Default, Default,
} }
const ALL_TAIL_REARS: [TailRear; 1] = [TailRear::Default]; const ALL_TAIL_REARS: [TailRear; 1] = [TailRear::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingInL { pub enum WingInL {
Default, Default,
} }
const ALL_WING_IN_LS: [WingInL; 1] = [WingInL::Default]; const ALL_WING_IN_LS: [WingInL; 1] = [WingInL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingInR { pub enum WingInR {
Default, Default,
} }
const ALL_WING_IN_RS: [WingInR; 1] = [WingInR::Default]; const ALL_WING_IN_RS: [WingInR; 1] = [WingInR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingOutL { pub enum WingOutL {
Default, Default,
} }
const ALL_WING_OUT_LS: [WingOutL; 1] = [WingOutL::Default]; const ALL_WING_OUT_LS: [WingOutL; 1] = [WingOutL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum WingOutR { pub enum WingOutR {
Default, Default,
} }
const ALL_WING_OUT_RS: [WingOutR; 1] = [WingOutR::Default]; const ALL_WING_OUT_RS: [WingOutR; 1] = [WingOutR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootFL { pub enum FootFL {
Default, Default,
} }
const ALL_FOOT_FLS: [FootFL; 1] = [FootFL::Default]; const ALL_FOOT_FLS: [FootFL; 1] = [FootFL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootFR { pub enum FootFR {
Default, Default,
} }
const ALL_FOOT_FRS: [FootFR; 1] = [FootFR::Default]; const ALL_FOOT_FRS: [FootFR; 1] = [FootFR::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootBL { pub enum FootBL {
Default, Default,
} }
const ALL_FOOT_BLS: [FootBL; 1] = [FootBL::Default]; const ALL_FOOT_BLS: [FootBL; 1] = [FootBL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootBR { pub enum FootBR {
Default, Default,
} }

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub torso: Torso, pub torso: Torso,
@ -24,36 +25,42 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Torso { pub enum Torso {
Default, Default,
} }
const ALL_TORSOS: [Torso; 1] = [Torso::Default]; const ALL_TORSOS: [Torso; 1] = [Torso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Rear { pub enum Rear {
Default, Default,
} }
const ALL_REARS: [Rear; 1] = [Rear::Default]; const ALL_REARS: [Rear; 1] = [Rear::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Tail { pub enum Tail {
Default, Default,
} }
const ALL_TAILS: [Tail; 1] = [Tail::Default]; const ALL_TAILS: [Tail; 1] = [Tail::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FinL { pub enum FinL {
Default, Default,
} }
const ALL_FIN_LS: [FinL; 1] = [FinL::Default]; const ALL_FIN_LS: [FinL; 1] = [FinL::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FinR { pub enum FinR {
Default, Default,
} }

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub torso: Torso, pub torso: Torso,
pub tail: Tail, pub tail: Tail,
@ -16,12 +17,14 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Torso { pub enum Torso {
Default, Default,
} }
const ALL_TORSOS: [Torso; 1] = [Torso::Default]; const ALL_TORSOS: [Torso; 1] = [Torso::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Tail { pub enum Tail {
Default, Default,
} }

View File

@ -1,14 +1,15 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head: Head, pub head: Head,
pub shoulder: Shoulder, pub shoulder: Shoulder,
pub chest: Chest, pub chest: Chest,
pub hand: Hand pub hand: Hand
pub belt: Belt, pub belt: Belt,
pub pants: Pants, pub pants: Pants,
pub foot: Foot, pub foot: Foot,
} }
impl Body { impl Body {
@ -27,40 +28,47 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Head { pub enum Head {
Default, Default,
} }
const ALL_HEADS: [Head; 1] = [Head::Default]; const ALL_HEADS: [Head; 1] = [Head::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Shoulder { pub enum Shoulder {
Default, Default,
} }
const ALL_SHOULDERS: [Shoulder; 1] = [Shoulder::Default]; const ALL_SHOULDERS: [Shoulder; 1] = [Shoulder::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Chest { pub enum Chest {
Default, Default,
} }
const ALL_CHESTS: [Chest; 1] = [Chest::Default]; const ALL_CHESTS: [Chest; 1] = [Chest::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Hand { pub enum Hand {
Default, Default,
} }
const ALL_HANDS: [Hand; 1] = [Hand::Default]; const ALL_HANDS: [Hand; 1] = [Hand::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Belt { pub enum Belt {
Default, Default,
} }
const ALL_BELTS: [Belt; 1] = [Belt::Default]; const ALL_BELTS: [Belt; 1] = [Belt::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Pants { pub enum Pants {
Default, Default,
} }
const ALL_FEET: [Foot; 1] = [Foot::Default]; const ALL_FEET: [Foot; 1] = [Foot::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Foot { pub enum Foot {
Default, Default,
} }

View File

@ -2,6 +2,7 @@ use rand::{seq::SliceRandom, thread_rng, Rng};
use vek::Rgb; use vek::Rgb;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub race: Race, pub race: Race,
pub body_type: BodyType, pub body_type: BodyType,
@ -59,13 +60,14 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Race { pub enum Race {
Danari, Danari = 0,
Dwarf, Dwarf = 1,
Elf, Elf = 2,
Human, Human = 3,
Orc, Orc = 4,
Undead, Undead = 5,
} }
pub const ALL_RACES: [Race; 6] = [ pub const ALL_RACES: [Race; 6] = [
Race::Danari, Race::Danari,
@ -379,21 +381,23 @@ impl Race {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum BodyType { pub enum BodyType {
Female, Female = 0,
Male, Male = 1,
} }
pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Chest { pub enum Chest {
Blue, Blue = 0,
Brown, Brown = 1,
Dark, Dark = 2,
Green, Green = 3,
Orange, Orange = 4,
Midnight, Midnight = 5,
Kimono, Kimono = 6,
} }
pub const ALL_CHESTS: [Chest; 7] = [ pub const ALL_CHESTS: [Chest; 7] = [
Chest::Blue, Chest::Blue,
@ -406,20 +410,22 @@ pub const ALL_CHESTS: [Chest; 7] = [
]; ];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Belt { pub enum Belt {
Dark, Dark = 0,
Cloth, Cloth = 1,
} }
pub const ALL_BELTS: [Belt; 2] = [Belt::Dark, Belt::Cloth]; pub const ALL_BELTS: [Belt; 2] = [Belt::Dark, Belt::Cloth];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Pants { pub enum Pants {
Blue, Blue = 0,
Brown, Brown = 1,
Dark, Dark = 2,
Green, Green = 3,
Orange, Orange = 4,
Kimono, Kimono = 5,
} }
pub const ALL_PANTS: [Pants; 6] = [ pub const ALL_PANTS: [Pants; 6] = [
Pants::Blue, Pants::Blue,
@ -431,47 +437,52 @@ pub const ALL_PANTS: [Pants; 6] = [
]; ];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Hand { pub enum Hand {
Bare, Bare = 0,
Cloth, Cloth = 1,
} }
pub const ALL_HANDS: [Hand; 2] = [Hand::Bare, Hand::Cloth]; pub const ALL_HANDS: [Hand; 2] = [Hand::Bare, Hand::Cloth];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Foot { pub enum Foot {
Bare, Bare = 0,
Dark, Dark = 1,
Sandal, Sandal = 2,
Jester, Jester = 3,
} }
pub const ALL_FEET: [Foot; 4] = [Foot::Bare, Foot::Dark, Foot::Sandal, Foot::Jester]; pub const ALL_FEET: [Foot; 4] = [Foot::Bare, Foot::Dark, Foot::Sandal, Foot::Jester];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Shoulder { pub enum Shoulder {
None, None = 0,
Brown1, Brown1 = 1,
Chain, Chain = 2,
} }
pub const ALL_SHOULDERS: [Shoulder; 3] = [Shoulder::None, Shoulder::Brown1, Shoulder::Chain]; pub const ALL_SHOULDERS: [Shoulder; 3] = [Shoulder::None, Shoulder::Brown1, Shoulder::Chain];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Eyebrows { pub enum Eyebrows {
Yup, Yup = 0,
} }
pub const ALL_EYEBROWS: [Eyebrows; 1] = [Eyebrows::Yup]; pub const ALL_EYEBROWS: [Eyebrows; 1] = [Eyebrows::Yup];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum EyeColor { pub enum EyeColor {
VigorousBlack, VigorousBlack = 0,
NobleBlue, NobleBlue = 1,
CuriousGreen, CuriousGreen = 2,
LoyalBrown, LoyalBrown = 3,
ViciousRed, ViciousRed = 4,
PumpkinOrange, PumpkinOrange = 5,
GhastlyYellow, GhastlyYellow = 6,
MagicPurple, MagicPurple = 7,
ToxicGreen, ToxicGreen = 8,
ExoticPurple, ExoticPurple = 9,
} }
impl EyeColor { impl EyeColor {
pub fn light_rgb(self) -> Rgb<u8> { pub fn light_rgb(self) -> Rgb<u8> {
@ -508,35 +519,37 @@ impl EyeColor {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Accessory { pub enum Accessory {
Nothing, Nothing = 0,
Some, Some = 1,
} }
pub const ALL_ACCESSORIES: [Accessory; 2] = [Accessory::Nothing, Accessory::Some]; pub const ALL_ACCESSORIES: [Accessory; 2] = [Accessory::Nothing, Accessory::Some];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Skin { pub enum Skin {
Pale, Pale = 0,
White, White = 1,
Tanned, Tanned = 2,
Brown, Brown = 3,
TannedBrown, TannedBrown = 4,
TannedDarkBrown, TannedDarkBrown = 5,
Iron, Iron = 6,
Steel, Steel = 7,
DanariOne, DanariOne = 8,
DanariTwo, DanariTwo = 9,
DanariThree, DanariThree = 10,
DanariFour, DanariFour = 11,
ElfOne, ElfOne = 12,
ElfTwo, ElfTwo = 13,
ElfThree, ElfThree = 14,
OrcOne, OrcOne = 15,
OrcTwo, OrcTwo = 16,
OrcThree, OrcThree = 17,
UndeadOne, UndeadOne = 18,
UndeadTwo, UndeadTwo = 19,
UndeadThree, UndeadThree = 20,
} }
impl Skin { impl Skin {
pub fn rgb(self) -> Rgb<u8> { pub fn rgb(self) -> Rgb<u8> {

View File

@ -1,58 +1,59 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Body { pub enum Body {
Arrow, Arrow = 0,
Bomb, Bomb = 1,
Scarecrow, Scarecrow = 2,
Cauldron, Cauldron = 3,
ChestVines, ChestVines = 4,
Chest, Chest = 5,
ChestDark, ChestDark = 6,
ChestDemon, ChestDemon = 7,
ChestGold, ChestGold = 8,
ChestLight, ChestLight = 9,
ChestOpen, ChestOpen = 10,
ChestSkull, ChestSkull = 11,
Pumpkin, Pumpkin = 12,
Pumpkin2, Pumpkin2 = 13,
Pumpkin3, Pumpkin3 = 14,
Pumpkin4, Pumpkin4 = 15,
Pumpkin5, Pumpkin5 = 16,
Campfire, Campfire = 17,
LanternGround, LanternGround = 18,
LanternGroundOpen, LanternGroundOpen = 19,
LanternStanding2, LanternStanding2 = 20,
LanternStanding, LanternStanding = 21,
PotionBlue, PotionBlue = 22,
PotionGreen, PotionGreen = 23,
PotionRed, PotionRed = 24,
Crate, Crate = 25,
Tent, Tent = 26,
WindowSpooky, WindowSpooky = 27,
DoorSpooky, DoorSpooky = 28,
Anvil, Anvil = 29,
Gravestone, Gravestone = 30,
Gravestone2, Gravestone2 = 31,
Bench, Bench = 32,
Chair, Chair = 33,
Chair2, Chair2 = 34,
Chair3, Chair3 = 35,
Table, Table = 36,
Table2, Table2 = 37,
Table3, Table3 = 38,
Drawer, Drawer = 39,
BedBlue, BedBlue = 40,
Carpet, Carpet = 41,
Bedroll, Bedroll = 42,
CarpetHumanRound, CarpetHumanRound = 43,
CarpetHumanSquare, CarpetHumanSquare = 44,
CarpetHumanSquare2, CarpetHumanSquare2 = 45,
CarpetHumanSquircle, CarpetHumanSquircle = 46,
Pouch, Pouch = 47,
CraftingBench, CraftingBench = 48,
BoltFire, BoltFire = 49,
ArrowSnake, ArrowSnake = 50,
} }
impl Body { impl Body {

View File

@ -1,6 +1,7 @@
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(C)]
pub struct Body { pub struct Body {
pub head_upper: HeadUpper, pub head_upper: HeadUpper,
pub jaw: Jaw, pub jaw: Jaw,
@ -35,66 +36,77 @@ impl Body {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum HeadUpper { pub enum HeadUpper {
Default, Default,
} }
const ALL_HEADS_UPPER: [HeadUpper; 1] = [HeadUpper::Default]; const ALL_HEADS_UPPER: [HeadUpper; 1] = [HeadUpper::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Jaw { pub enum Jaw {
Default, Default,
} }
const ALL_JAWS: [Jaw; 1] = [Jaw::Default]; const ALL_JAWS: [Jaw; 1] = [Jaw::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum HeadLower { pub enum HeadLower {
Default, Default,
} }
const ALL_HEADS_LOWER: [HeadLower; 1] = [HeadLower::Default]; const ALL_HEADS_LOWER: [HeadLower; 1] = [HeadLower::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Tail { pub enum Tail {
Default, Default,
} }
const ALL_TAILS: [Tail; 1] = [Tail::Default]; const ALL_TAILS: [Tail; 1] = [Tail::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum TorsoBack { pub enum TorsoBack {
Default, Default,
} }
const ALL_TORSOS_BACK: [TorsoBack; 1] = [TorsoBack::Default]; const ALL_TORSOS_BACK: [TorsoBack; 1] = [TorsoBack::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum TorsoMid { pub enum TorsoMid {
Default, Default,
} }
const ALL_TORSOS_MID: [TorsoMid; 1] = [TorsoMid::Default]; const ALL_TORSOS_MID: [TorsoMid; 1] = [TorsoMid::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Ears { pub enum Ears {
Default, Default,
} }
const ALL_EARS: [Ears; 1] = [Ears::Default]; const ALL_EARS: [Ears; 1] = [Ears::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootLF { pub enum FootLF {
Default, Default,
} }
const ALL_FEETS_LF: [FootLF; 1] = [FootLF::Default]; const ALL_FEETS_LF: [FootLF; 1] = [FootLF::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootRF { pub enum FootRF {
Default, Default,
} }
const ALL_FEETS_RF: [FootRF; 1] = [FootRF::Default]; const ALL_FEETS_RF: [FootRF; 1] = [FootRF::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootLB { pub enum FootLB {
Default, Default,
} }
const ALL_FEETS_LB: [FootLB; 1] = [FootLB::Default]; const ALL_FEETS_LB: [FootLB; 1] = [FootLB::Default];
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum FootRB { pub enum FootRB {
Default, Default,
} }

View File

@ -1,6 +1,6 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![type_length_limit = "1664759"] #![type_length_limit = "1664759"]
#![feature(trait_alias)] #![feature(trait_alias, arbitrary_enum_discriminant)]
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;

View File

@ -62,9 +62,10 @@ crossbeam = "=0.7.2"
hashbrown = { version = "0.6.2", features = ["serde", "nightly"] } hashbrown = { version = "0.6.2", features = ["serde", "nightly"] }
chrono = "0.4.9" chrono = "0.4.9"
rust-argon2 = "0.5" rust-argon2 = "0.5"
bincode = "1.2"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
dispatch = "0.1.4" dispatch = "0.1.4"
[target.'cfg(windows)'.build-dependencies] [target.'cfg(windows)'.build-dependencies]
winres = "0.1" winres = "0.1"

View File

@ -13,6 +13,7 @@ pub mod key_state;
mod logging; mod logging;
pub mod menu; pub mod menu;
pub mod mesh; pub mod mesh;
pub mod meta;
pub mod render; pub mod render;
pub mod scene; pub mod scene;
pub mod session; pub mod session;
@ -24,13 +25,16 @@ pub mod window;
// Reexports // Reexports
pub use crate::error::Error; pub use crate::error::Error;
use crate::{audio::AudioFrontend, menu::main::MainMenuState, settings::Settings, window::Window}; use crate::{
audio::AudioFrontend, menu::main::MainMenuState, meta::Meta, settings::Settings, window::Window,
};
use log::{debug, error}; use log::{debug, error};
use std::{mem, panic, str::FromStr}; use std::{mem, panic, str::FromStr};
/// A type used to store state that is shared between all play states. /// A type used to store state that is shared between all play states.
pub struct GlobalState { pub struct GlobalState {
settings: Settings, settings: Settings,
meta: Meta,
window: Window, window: Window,
audio: AudioFrontend, audio: AudioFrontend,
info_message: Option<String>, info_message: Option<String>,
@ -97,6 +101,9 @@ fn main() {
logging::init(&settings, term_log_level, file_log_level); logging::init(&settings, term_log_level, file_log_level);
// Load metadata
let meta = Meta::load();
// Save settings to add new fields or create the file if it is not already there // Save settings to add new fields or create the file if it is not already there
if let Err(err) = settings.save_to_file() { if let Err(err) = settings.save_to_file() {
panic!("Failed to save settings: {:?}", err); panic!("Failed to save settings: {:?}", err);
@ -120,6 +127,7 @@ fn main() {
audio, audio,
window: Window::new(&settings).expect("Failed to create window!"), window: Window::new(&settings).expect("Failed to create window!"),
settings, settings,
meta,
info_message: None, info_message: None,
}; };
@ -254,6 +262,7 @@ fn main() {
} }
} }
// Save any unsaved changes to settings // Save any unsaved changes to settings and meta
global_state.settings.save_to_file_warn(); global_state.settings.save_to_file_warn();
global_state.meta.save_to_file_warn();
} }

View File

@ -57,7 +57,7 @@ impl PlayState for CharSelectionState {
// Maintain the UI. // Maintain the UI.
let events = self let events = self
.char_selection_ui .char_selection_ui
.maintain(global_state.window.renderer_mut(), &self.client.borrow()); .maintain(global_state, &self.client.borrow());
for event in events { for event in events {
match event { match event {
ui::Event::Logout => { ui::Event::Logout => {

View File

@ -1,5 +1,6 @@
use crate::window::{Event as WinEvent, PressState}; use crate::window::{Event as WinEvent, PressState};
use crate::{ use crate::{
meta::CharacterData,
render::{Consts, Globals, Renderer}, render::{Consts, Globals, Renderer},
ui::{ ui::{
img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic, VoxelMs9Graphic}, img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic, VoxelMs9Graphic},
@ -8,7 +9,7 @@ use crate::{
GlobalState, GlobalState,
}; };
use client::Client; use client::Client;
use common::comp::humanoid; use common::comp::{self, humanoid};
use conrod_core::{ use conrod_core::{
color, color,
color::TRANSPARENT, color::TRANSPARENT,
@ -43,7 +44,6 @@ widget_ids! {
divider, divider,
bodyrace_text, bodyrace_text,
facialfeatures_text, facialfeatures_text,
char_delete,
info_bg, info_bg,
info_frame, info_frame,
info_button_align, info_button_align,
@ -61,10 +61,11 @@ widget_ids! {
// Characters // Characters
character_box_1, character_boxes[],
character_name_1, character_deletes[],
character_location_1, character_names[],
character_level_1, character_locations[],
character_levels[],
character_box_2, character_box_2,
character_name_2, character_name_2,
@ -242,7 +243,8 @@ const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
const TEXT_COLOR_2: Color = Color::Rgba(1.0, 1.0, 1.0, 0.2); const TEXT_COLOR_2: Color = Color::Rgba(1.0, 1.0, 1.0, 0.2);
enum InfoContent { enum InfoContent {
Deletion, None,
Deletion(usize),
//Name, //Name,
} }
@ -254,7 +256,6 @@ pub struct CharSelectionUi {
fonts: Fonts, fonts: Fonts,
character_creation: bool, character_creation: bool,
info_content: InfoContent, info_content: InfoContent,
info_window: bool,
//deletion_confirmation: bool, //deletion_confirmation: bool,
pub character_name: String, pub character_name: String,
pub character_body: humanoid::Body, pub character_body: humanoid::Body,
@ -283,8 +284,7 @@ impl CharSelectionUi {
imgs, imgs,
rot_imgs, rot_imgs,
fonts, fonts,
info_window: false, info_content: InfoContent::None,
info_content: InfoContent::Deletion,
//deletion_confirmation: false, //deletion_confirmation: false,
character_creation: false, character_creation: false,
character_name: "Character Name".to_string(), character_name: "Character Name".to_string(),
@ -294,7 +294,7 @@ impl CharSelectionUi {
} }
// TODO: Split this into multiple modules or functions. // TODO: Split this into multiple modules or functions.
fn update_layout(&mut self, client: &Client) -> Vec<Event> { fn update_layout(&mut self, global_state: &mut GlobalState, client: &Client) -> Vec<Event> {
let mut events = Vec::new(); let mut events = Vec::new();
let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets(); let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets();
let version = format!( let version = format!(
@ -322,7 +322,8 @@ impl CharSelectionUi {
.desc_text_color(TEXT_COLOR_2); .desc_text_color(TEXT_COLOR_2);
// Information Window // Information Window
if self.info_window { if let InfoContent::None = self.info_content {
} else {
Rectangle::fill_with([520.0, 150.0], color::rgba(0.0, 0.0, 0.0, 0.9)) Rectangle::fill_with([520.0, 150.0], color::rgba(0.0, 0.0, 0.0, 0.9))
.mid_top_with_margin_on(ui_widgets.window, 300.0) .mid_top_with_margin_on(ui_widgets.window, 300.0)
.set(self.ids.info_bg, ui_widgets); .set(self.ids.info_bg, ui_widgets);
@ -334,7 +335,8 @@ impl CharSelectionUi {
.bottom_left_with_margins_on(self.ids.info_frame, 0.0, 0.0) .bottom_left_with_margins_on(self.ids.info_frame, 0.0, 0.0)
.set(self.ids.info_button_align, ui_widgets); .set(self.ids.info_button_align, ui_widgets);
match self.info_content { match self.info_content {
InfoContent::Deletion => { InfoContent::None => unreachable!(),
InfoContent::Deletion(character_index) => {
Text::new("Permanently delete this Character?") Text::new("Permanently delete this Character?")
.mid_top_with_margin_on(self.ids.info_frame, 40.0) .mid_top_with_margin_on(self.ids.info_frame, 40.0)
.font_size(24) .font_size(24)
@ -354,29 +356,44 @@ impl CharSelectionUi {
.set(self.ids.info_no, ui_widgets) .set(self.ids.info_no, ui_widgets)
.was_clicked() .was_clicked()
{ {
self.info_window = false self.info_content = InfoContent::None;
}; };
if Button::image(self.imgs.button) if Button::image(self.imgs.button)
.w_h(150.0, 40.0) .w_h(150.0, 40.0)
.right_from(self.ids.info_no, 100.0) .right_from(self.ids.info_no, 100.0)
//.hover_image(self.imgs.button_hover) .hover_image(self.imgs.button_hover)
//.press_image(self.imgs.button_press) .press_image(self.imgs.button_press)
.label_y(Relative::Scalar(2.0)) .label_y(Relative::Scalar(2.0))
.label("Yes") .label("Yes")
.label_font_size(18)
.label_font_id(self.fonts.cyri) .label_font_id(self.fonts.cyri)
.label_color(Color::Rgba(1.0, 1.0, 1.0, 0.1)) .label_font_size(18)
.label_color(TEXT_COLOR)
.set(self.ids.info_ok, ui_widgets) .set(self.ids.info_ok, ui_widgets)
.was_clicked() .was_clicked()
{ {
//self.info_window = false self.info_content = InfoContent::None;
// TODO -> Char Deletion Event global_state.meta.delete_character(character_index);
}; };
} }
} }
} }
// Character Selection ///////////////// // Character Selection /////////////////
if !self.character_creation { if !self.character_creation {
// Set active body
self.character_body = if let Some(character) = global_state
.meta
.characters
.get(global_state.meta.selected_character)
{
match character.body {
comp::Body::Humanoid(body) => Some(body.clone()),
_ => None,
}
} else {
None
}
.unwrap_or_else(|| humanoid::Body::random());
// Background for Server Frame // Background for Server Frame
Rectangle::fill_with([386.0, 95.0], color::rgba(0.0, 0.0, 0.0, 0.9)) Rectangle::fill_with([386.0, 95.0], color::rgba(0.0, 0.0, 0.0, 0.9))
.top_left_with_margins_on(ui_widgets.window, 30.0, 30.0) .top_left_with_margins_on(ui_widgets.window, 30.0, 30.0)
@ -489,54 +506,96 @@ impl CharSelectionUi {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(self.ids.version, ui_widgets); .set(self.ids.version, ui_widgets);
// 1st Character in Selection List // Resize character selection widgets
if Button::image(self.imgs.selection) let character_count = global_state.meta.characters.len();
.top_left_with_margins_on(self.ids.charlist_alignment, 0.0, 2.0) self.ids
.w_h(386.0, 80.0) .character_boxes
.image_color(Color::Rgba(1.0, 1.0, 1.0, 0.8)) .resize(character_count, &mut ui_widgets.widget_id_generator());
.hover_image(self.imgs.selection) self.ids
.press_image(self.imgs.selection) .character_deletes
.label_font_id(self.fonts.cyri) .resize(character_count, &mut ui_widgets.widget_id_generator());
.label_y(conrod_core::position::Relative::Scalar(20.0)) self.ids
.set(self.ids.character_box_1, ui_widgets) .character_names
.was_clicked() .resize(character_count, &mut ui_widgets.widget_id_generator());
{} self.ids
if Button::image(self.imgs.delete_button) .character_levels
.w_h(30.0 * 0.5, 30.0 * 0.5) .resize(character_count, &mut ui_widgets.widget_id_generator());
.top_right_with_margins_on(self.ids.character_box_1, 15.0, 15.0) self.ids
.hover_image(self.imgs.delete_button_hover) .character_locations
.press_image(self.imgs.delete_button_press) .resize(character_count, &mut ui_widgets.widget_id_generator());
.with_tooltip(tooltip_manager, "Delete Character", "", &tooltip_human)
.set(self.ids.char_delete, ui_widgets) // Character selection
.was_clicked() for (i, character) in global_state.meta.characters.iter().enumerate() {
{ let character_box = Button::image(if global_state.meta.selected_character == i {
self.info_content = InfoContent::Deletion; self.imgs.selection_hover
self.info_window = true; } else {
self.imgs.selection
});
let character_box = if i == 0 {
character_box.top_left_with_margins_on(self.ids.charlist_alignment, 0.0, 2.0)
} else {
character_box.down_from(self.ids.character_boxes[i - 1], 5.0)
};
if character_box
.w_h(386.0, 80.0)
.image_color(Color::Rgba(1.0, 1.0, 1.0, 0.8))
.hover_image(self.imgs.selection_hover)
.press_image(self.imgs.selection_press)
.label_font_id(self.fonts.cyri)
.label_y(conrod_core::position::Relative::Scalar(20.0))
.set(self.ids.character_boxes[i], ui_widgets)
.was_clicked()
{
self.character_name = character.name.clone();
self.character_body = match &character.body {
comp::Body::Humanoid(body) => body.clone(),
_ => panic!("Unsupported body type!"),
};
global_state.meta.selected_character = i;
}
if Button::image(self.imgs.delete_button)
.w_h(30.0 * 0.5, 30.0 * 0.5)
.top_right_with_margins_on(self.ids.character_boxes[i], 15.0, 15.0)
.hover_image(self.imgs.delete_button_hover)
.press_image(self.imgs.delete_button_press)
.with_tooltip(tooltip_manager, "Delete Character", "", &tooltip_human)
.set(self.ids.character_deletes[i], ui_widgets)
.was_clicked()
{
self.info_content = InfoContent::Deletion(i);
}
Text::new(&character.name)
.top_left_with_margins_on(self.ids.character_boxes[i], 6.0, 9.0)
.font_size(19)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_names[i], ui_widgets);
Text::new("Level <n/a>")
.down_from(self.ids.character_names[i], 4.0)
.font_size(17)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_levels[i], ui_widgets);
Text::new("Uncanny Valley")
.down_from(self.ids.character_levels[i], 4.0)
.font_size(17)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_locations[i], ui_widgets);
} }
Text::new("Test Character")
.top_left_with_margins_on(self.ids.character_box_1, 6.0, 9.0)
.font_size(19)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_name_1, ui_widgets);
Text::new("Level 1")
.down_from(self.ids.character_name_1, 4.0)
.font_size(17)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_level_1, ui_widgets);
Text::new("Uncanny Valley")
.down_from(self.ids.character_level_1, 4.0)
.font_size(17)
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(self.ids.character_location_1, ui_widgets);
// Create Character Button // Create Character Button
if Button::image(self.imgs.selection) let create_char_button = Button::image(self.imgs.selection);
.down_from(self.ids.character_box_1, 5.0)
let create_char_button = if character_count > 0 {
create_char_button.down_from(self.ids.character_boxes[character_count - 1], 5.0)
} else {
create_char_button.top_left_with_margins_on(self.ids.charlist_alignment, 0.0, 2.0)
};
if create_char_button
.w_h(386.0, 80.0) .w_h(386.0, 80.0)
.hover_image(self.imgs.selection_hover) .hover_image(self.imgs.selection_hover)
.press_image(self.imgs.selection_press) .press_image(self.imgs.selection_press)
@ -549,6 +608,7 @@ impl CharSelectionUi {
{ {
self.character_creation = true; self.character_creation = true;
self.character_tool = Some(STARTER_SWORD); self.character_tool = Some(STARTER_SWORD);
self.character_body = humanoid::Body::random();
} }
} }
// Character_Creation ////////////////////////////////////////////////////////////////////// // Character_Creation //////////////////////////////////////////////////////////////////////
@ -585,6 +645,10 @@ impl CharSelectionUi {
{ {
// TODO: Save character. // TODO: Save character.
self.character_creation = false; self.character_creation = false;
global_state.meta.add_character(CharacterData {
name: self.character_name.clone(),
body: comp::Body::Humanoid(self.character_body.clone()),
});
} }
// Character Name Input // Character Name Input
Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97)) Rectangle::fill_with([320.0, 50.0], color::rgba(0.0, 0.0, 0.0, 0.97))
@ -1186,9 +1250,9 @@ impl CharSelectionUi {
} }
} }
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) -> Vec<Event> { pub fn maintain(&mut self, global_state: &mut GlobalState, client: &Client) -> Vec<Event> {
let events = self.update_layout(client); let events = self.update_layout(global_state, client);
self.ui.maintain(renderer, None); self.ui.maintain(global_state.window.renderer_mut(), None);
events events
} }

View File

@ -223,8 +223,9 @@ impl MainMenuUi {
\n\ \n\
The name you put in will be your character name ingame.\n\ The name you put in will be your character name ingame.\n\
\n\ \n\
As of now you can't save your characters.\n\ Character names and appearances will be saved on your computer.\n\
Changing their appearance is possible though."; \n\
Levels/Items are not saved yet.";
// Tooltip // Tooltip
let _tooltip = Tooltip::new({ let _tooltip = Tooltip::new({

89
voxygen/src/meta.rs Normal file
View File

@ -0,0 +1,89 @@
use common::comp;
use directories::ProjectDirs;
use log::warn;
use serde_derive::{Deserialize, Serialize};
use std::{fs, io, path::PathBuf};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[repr(C)]
pub struct CharacterData {
pub name: String,
pub body: comp::Body,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
#[repr(C)]
pub struct Meta {
pub characters: Vec<CharacterData>,
pub selected_character: usize,
}
impl Meta {
pub fn delete_character(&mut self, index: usize) {
self.characters.remove(index);
if index < self.selected_character {
self.selected_character -= 1;
}
}
pub fn add_character(&mut self, data: CharacterData) {
self.characters.push(data);
}
pub fn load() -> Self {
let path = Self::get_meta_path();
if let Ok(file) = fs::File::open(&path) {
match bincode::deserialize_from(file) {
Ok(s) => return s,
Err(e) => {
log::warn!("Failed to parse meta file! Fallback to default. {}", e);
// Rename the corrupted settings file
let mut new_path = path.to_owned();
new_path.pop();
new_path.push("meta.invalid.dat");
if let Err(err) = std::fs::rename(path, new_path) {
log::warn!("Failed to rename meta file. {}", err);
}
}
}
}
// This is reached if either:
// - The file can't be opened (presumably it doesn't exist)
// - Or there was an error parsing the file
let default = Self::default();
default.save_to_file_warn();
default
}
pub fn save_to_file_warn(&self) {
if let Err(err) = self.save_to_file() {
warn!("Failed to save settings: {:?}", err);
}
}
pub fn save_to_file(&self) -> std::io::Result<()> {
let path = Self::get_meta_path();
if let Some(dir) = path.parent() {
fs::create_dir_all(dir)?;
}
bincode::serialize_into(fs::File::create(path)?, self)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Ok(())
}
pub fn get_meta_path() -> PathBuf {
if let Some(val) = std::env::var_os("VOXYGEN_CONFIG") {
let meta = PathBuf::from(val).join("meta.dat");
if meta.exists() || meta.parent().map(|x| x.exists()).unwrap_or(false) {
return meta;
}
log::warn!("VOXYGEN_CONFIG points to invalid path.");
}
let proj_dirs = ProjectDirs::from("net", "veloren", "voxygen")
.expect("System's $HOME directory path not found!");
proj_dirs.config_dir().join("meta").with_extension("dat")
}
}