mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Switched to actor system
Former-commit-id: d2a482f6209aff7aaa4e747e35ce4a7c8a79cdfc
This commit is contained in:
parent
ba10ca38ba
commit
761c6e9cf8
@ -13,7 +13,7 @@ pub enum Race {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Gender {
|
||||
pub enum BodyType {
|
||||
Female,
|
||||
Male,
|
||||
Unspecified,
|
||||
@ -21,32 +21,32 @@ pub enum Gender {
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Head {
|
||||
DefaultHead,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Chest {
|
||||
DefaultChest,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Belt {
|
||||
DefaultBelt,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Pants {
|
||||
DefaultPants,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Hand {
|
||||
DefaultHand,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Foot {
|
||||
DefaultFoot,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@ -62,42 +62,45 @@ pub enum Weapon {
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Shoulder {
|
||||
DefaultShoulder,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Draw {
|
||||
DefaultDraw,
|
||||
Default,
|
||||
}
|
||||
|
||||
use Belt::*;
|
||||
use Chest::*;
|
||||
use Draw::*;
|
||||
use Foot::*;
|
||||
use Gender::*;
|
||||
use Hand::*;
|
||||
use Head::*;
|
||||
use Pants::*;
|
||||
use Race::*;
|
||||
use Shoulder::*;
|
||||
use Weapon::*;
|
||||
|
||||
const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead];
|
||||
const ALL_GENDERS: [Gender; 3] = [Female, Male, Unspecified];
|
||||
const ALL_HEADS: [Head; 1] = [DefaultHead];
|
||||
const ALL_CHESTS: [Chest; 1] = [DefaultChest];
|
||||
const ALL_BELTS: [Belt; 1] = [DefaultBelt];
|
||||
const ALL_PANTS: [Pants; 1] = [DefaultPants];
|
||||
const ALL_HANDS: [Hand; 1] = [DefaultHand];
|
||||
const ALL_FEET: [Foot; 1] = [DefaultFoot];
|
||||
const ALL_WEAPONS: [Weapon; 7] = [Daggers, SwordShield, Sword, Axe, Hammer, Bow, Staff];
|
||||
const ALL_SHOULDERS: [Shoulder; 1] = [DefaultShoulder];
|
||||
const ALL_DRAW: [Draw; 1] = [DefaultDraw];
|
||||
const ALL_RACES: [Race; 6] = [
|
||||
Race::Danari,
|
||||
Race::Dwarf,
|
||||
Race::Elf,
|
||||
Race::Human,
|
||||
Race::Orc,
|
||||
Race::Undead,
|
||||
];
|
||||
const ALL_BODY_TYPES: [BodyType; 3] = [BodyType::Female, BodyType::Male, BodyType::Unspecified];
|
||||
const ALL_HEADS: [Head; 1] = [Head::Default];
|
||||
const ALL_CHESTS: [Chest; 1] = [Chest::Default];
|
||||
const ALL_BELTS: [Belt; 1] = [Belt::Default];
|
||||
const ALL_PANTS: [Pants; 1] = [Pants::Default];
|
||||
const ALL_HANDS: [Hand; 1] = [Hand::Default];
|
||||
const ALL_FEET: [Foot; 1] = [Foot::Default];
|
||||
const ALL_WEAPONS: [Weapon; 7] = [
|
||||
Weapon::Daggers,
|
||||
Weapon::SwordShield,
|
||||
Weapon::Sword,
|
||||
Weapon::Axe,
|
||||
Weapon::Hammer,
|
||||
Weapon::Bow,
|
||||
Weapon::Staff,
|
||||
];
|
||||
const ALL_SHOULDERS: [Shoulder; 1] = [Shoulder::Default];
|
||||
const ALL_DRAW: [Draw; 1] = [Draw::Default];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Character {
|
||||
pub struct HumanoidBody {
|
||||
pub race: Race,
|
||||
pub gender: Gender,
|
||||
pub body_type: BodyType,
|
||||
pub head: Head,
|
||||
pub chest: Chest,
|
||||
pub belt: Belt,
|
||||
@ -109,11 +112,11 @@ pub struct Character {
|
||||
pub draw: Draw,
|
||||
}
|
||||
|
||||
impl Character {
|
||||
impl HumanoidBody {
|
||||
pub fn random() -> Self {
|
||||
Self {
|
||||
race: *thread_rng().choose(&ALL_RACES).unwrap(),
|
||||
gender: *thread_rng().choose(&ALL_GENDERS).unwrap(),
|
||||
body_type: *thread_rng().choose(&ALL_BODY_TYPES).unwrap(),
|
||||
head: *thread_rng().choose(&ALL_HEADS).unwrap(),
|
||||
chest: *thread_rng().choose(&ALL_CHESTS).unwrap(),
|
||||
belt: *thread_rng().choose(&ALL_BELTS).unwrap(),
|
||||
@ -127,6 +130,23 @@ impl Character {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Body {
|
||||
Humanoid(HumanoidBody),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Actor {
|
||||
Character {
|
||||
name: String,
|
||||
body: Body,
|
||||
},
|
||||
}
|
||||
|
||||
impl Component for Actor {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AnimationHistory {
|
||||
pub last: Option<Animation>,
|
||||
@ -151,10 +171,6 @@ pub enum Animation {
|
||||
Jump,
|
||||
}
|
||||
|
||||
impl Component for Character {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
impl Component for AnimationHistory {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
pub mod agent;
|
||||
pub mod character;
|
||||
pub mod actor;
|
||||
pub mod phys;
|
||||
pub mod player;
|
||||
|
||||
// Reexports
|
||||
pub use agent::{Agent, Control};
|
||||
pub use character::Animation;
|
||||
pub use character::AnimationHistory;
|
||||
pub use character::Character;
|
||||
pub use actor::Animation;
|
||||
pub use actor::AnimationHistory;
|
||||
pub use actor::HumanoidBody;
|
||||
pub use actor::Body;
|
||||
pub use actor::Actor;
|
||||
pub use player::Player;
|
||||
|
@ -7,12 +7,15 @@ pub enum ClientMsg {
|
||||
Register {
|
||||
player: comp::Player,
|
||||
},
|
||||
Character(comp::Character),
|
||||
Character {
|
||||
name: String,
|
||||
body: comp::HumanoidBody,
|
||||
},
|
||||
RequestState(ClientState),
|
||||
Ping,
|
||||
Pong,
|
||||
Chat(String),
|
||||
PlayerAnimation(comp::character::AnimationHistory),
|
||||
PlayerAnimation(comp::AnimationHistory),
|
||||
PlayerPhysics {
|
||||
pos: comp::phys::Pos,
|
||||
vel: comp::phys::Vel,
|
||||
|
@ -9,7 +9,7 @@ sphynx::sum_type! {
|
||||
Pos(comp::phys::Pos),
|
||||
Vel(comp::phys::Vel),
|
||||
Dir(comp::phys::Dir),
|
||||
Character(comp::Character),
|
||||
Actor(comp::Actor),
|
||||
Player(comp::Player),
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ sphynx::sum_type! {
|
||||
Pos(PhantomData<comp::phys::Pos>),
|
||||
Vel(PhantomData<comp::phys::Vel>),
|
||||
Dir(PhantomData<comp::phys::Dir>),
|
||||
Character(PhantomData<comp::Character>),
|
||||
Actor(PhantomData<comp::Actor>),
|
||||
Player(PhantomData<comp::Player>),
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl State {
|
||||
// Create a new Sphynx ECS world
|
||||
fn setup_sphynx_world(ecs: &mut sphynx::World<EcsPacket>) {
|
||||
// Register synced components
|
||||
ecs.register_synced::<comp::Character>();
|
||||
ecs.register_synced::<comp::Actor>();
|
||||
ecs.register_synced::<comp::Player>();
|
||||
|
||||
// Register unsynched (or synced by other means) components
|
||||
|
@ -191,26 +191,14 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha
|
||||
.read_component_cloned::<comp::phys::Pos>(entity)
|
||||
{
|
||||
Some(pos) => {
|
||||
let mut current = entity;
|
||||
|
||||
for _ in 0..1 {
|
||||
current = server
|
||||
.create_npc(comp::Character::random())
|
||||
.with(comp::Control::default())
|
||||
.with(comp::Agent::Pet {
|
||||
target: current,
|
||||
offset: Vec2::zero(),
|
||||
})
|
||||
.with(pos)
|
||||
.build();
|
||||
}
|
||||
server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::Chat("Pet spawned!".to_owned()));
|
||||
}
|
||||
None => server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
|
||||
server.create_npc("Bungo".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random()))
|
||||
.with(comp::Control::default())
|
||||
.with(comp::Agent::Pet{ target: entity, offset: Vec2::zero() })
|
||||
.with(pos)
|
||||
.build();
|
||||
server.clients.notify(entity, ServerMsg::Chat("Spawned pet!".to_owned()));
|
||||
},
|
||||
None => server.clients.notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
comp,
|
||||
comp::character::Animation,
|
||||
msg::{ClientMsg, ClientState, RequestStateError, ServerMsg},
|
||||
net::PostOffice,
|
||||
state::{State, Uid},
|
||||
@ -81,7 +80,7 @@ impl Server {
|
||||
};
|
||||
|
||||
for i in 0..4 {
|
||||
this.create_npc(comp::Character::random())
|
||||
this.create_npc("Tobermory".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random()))
|
||||
.with(comp::Control::default())
|
||||
.with(comp::Agent::Wanderer(Vec2::zero()))
|
||||
.build();
|
||||
@ -114,24 +113,31 @@ impl Server {
|
||||
|
||||
/// Build a non-player character
|
||||
#[allow(dead_code)]
|
||||
pub fn create_npc(&mut self, character: comp::Character) -> EcsEntityBuilder {
|
||||
pub fn create_npc(&mut self, name: String, body: comp::Body) -> EcsEntityBuilder {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)))
|
||||
.with(comp::phys::Vel(Vec3::zero()))
|
||||
.with(comp::phys::Dir(Vec3::unit_y()))
|
||||
.with(comp::AnimationHistory::new(Animation::Idle))
|
||||
.with(character)
|
||||
.with(comp::AnimationHistory::new(comp::Animation::Idle))
|
||||
.with(comp::Actor::Character {
|
||||
name,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_player_character(
|
||||
state: &mut State,
|
||||
entity: EcsEntity,
|
||||
client: &mut Client,
|
||||
character: comp::Character,
|
||||
name: String,
|
||||
body: comp::HumanoidBody,
|
||||
) {
|
||||
state.write_component(entity, character);
|
||||
state.write_component(entity, comp::Actor::Character {
|
||||
name,
|
||||
body: comp::Body::Humanoid(body),
|
||||
});
|
||||
state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)));
|
||||
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
|
||||
@ -139,7 +145,10 @@ impl Server {
|
||||
state.write_component(entity, comp::phys::ForceUpdate);
|
||||
|
||||
// Set initial animation
|
||||
state.write_component(entity, comp::AnimationHistory::new(Animation::Idle));
|
||||
state.write_component(
|
||||
entity,
|
||||
comp::AnimationHistory::new(comp::Animation::Idle),
|
||||
);
|
||||
|
||||
// Tell the client his request was successful
|
||||
client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character)));
|
||||
@ -337,13 +346,13 @@ impl Server {
|
||||
// Use RequestState instead (No need to send `player` again)
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::Character(character) => match client.client_state {
|
||||
ClientMsg::Character { name, body } => match client.client_state {
|
||||
// Become Registered first
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Registered | ClientState::Spectator => {
|
||||
Self::create_player_character(state, entity, client, character)
|
||||
Self::create_player_character(state, entity, client, name, body)
|
||||
}
|
||||
ClientState::Character => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
|
@ -76,7 +76,10 @@ impl PlayState for CharSelectionState {
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.postbox
|
||||
.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
||||
.send_message(ClientMsg::Character {
|
||||
name: self.char_selection_ui.character_name.clone(),
|
||||
body: self.char_selection_ui.character_body,
|
||||
});
|
||||
return PlayStateResult::Switch(Box::new(SessionState::new(
|
||||
&mut global_state.window,
|
||||
self.client.clone(),
|
||||
|
@ -1,3 +1,9 @@
|
||||
use vek::*;
|
||||
use client::Client;
|
||||
use common::{
|
||||
comp::HumanoidBody,
|
||||
figure::Segment,
|
||||
};
|
||||
use crate::{
|
||||
anim::{
|
||||
character::{CharacterSkeleton, IdleAnimation},
|
||||
@ -12,9 +18,6 @@ use crate::{
|
||||
figure::{FigureModelCache, FigureState},
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
use common::{comp::Character, figure::Segment};
|
||||
use vek::*;
|
||||
|
||||
struct Skybox {
|
||||
model: Model<SkyboxPipeline>,
|
||||
@ -108,7 +111,7 @@ impl Scene {
|
||||
|
||||
let model = self.figure_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
Character::random(),
|
||||
HumanoidBody::random(),
|
||||
client.get_tick(),
|
||||
);
|
||||
renderer.render_figure(
|
||||
|
@ -7,8 +7,11 @@ use crate::{
|
||||
},
|
||||
window::Window,
|
||||
};
|
||||
use common::comp::character::{
|
||||
Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon,
|
||||
use common::comp::{
|
||||
HumanoidBody,
|
||||
actor::{
|
||||
Belt, Chest, Foot, BodyType, Hand, Head, Pants, Race, Weapon,
|
||||
},
|
||||
};
|
||||
use conrod_core::{
|
||||
color,
|
||||
@ -37,7 +40,7 @@ widget_ids! {
|
||||
weapon_heading,
|
||||
weapon_description,
|
||||
races_bg,
|
||||
gender_bg,
|
||||
body_type_bg,
|
||||
desc_bg,
|
||||
skin_eyes_window,
|
||||
hair_window,
|
||||
@ -71,8 +74,8 @@ widget_ids! {
|
||||
race_4,
|
||||
race_5,
|
||||
race_6,
|
||||
gender_1,
|
||||
gender_2,
|
||||
body_type_1,
|
||||
body_type_2,
|
||||
weapon_1,
|
||||
weapon_2,
|
||||
weapon_3,
|
||||
@ -267,8 +270,8 @@ pub struct CharSelectionUi {
|
||||
fonts: Fonts,
|
||||
character_creation: bool,
|
||||
selected_char_no: Option<i32>,
|
||||
character_name: String,
|
||||
pub character: Character,
|
||||
pub character_name: String,
|
||||
pub character_body: HumanoidBody,
|
||||
creation_state: CreationState,
|
||||
}
|
||||
|
||||
@ -293,7 +296,7 @@ impl CharSelectionUi {
|
||||
character_creation: false,
|
||||
selected_char_no: None,
|
||||
character_name: "Character Name".to_string(),
|
||||
character: Character::random(),
|
||||
character_body: HumanoidBody::random(),
|
||||
creation_state: CreationState::Race,
|
||||
}
|
||||
}
|
||||
@ -597,14 +600,14 @@ impl CharSelectionUi {
|
||||
// for alignment
|
||||
Rectangle::fill_with([151.0, 68.0], color::TRANSPARENT)
|
||||
.mid_top_with_margin_on(self.ids.creation_window, 210.0)
|
||||
.set(self.ids.gender_bg, ui_widgets);
|
||||
.set(self.ids.body_type_bg, ui_widgets);
|
||||
|
||||
// Male
|
||||
Image::new(self.imgs.male)
|
||||
.w_h(68.0, 68.0)
|
||||
.mid_left_of(self.ids.gender_bg)
|
||||
.mid_left_of(self.ids.body_type_bg)
|
||||
.set(self.ids.male, ui_widgets);
|
||||
if Button::image(if let Gender::Male = self.character.gender {
|
||||
if Button::image(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -612,17 +615,17 @@ impl CharSelectionUi {
|
||||
.middle_of(self.ids.male)
|
||||
.hover_image(self.imgs.icon_border_mo)
|
||||
.press_image(self.imgs.icon_border_press)
|
||||
.set(self.ids.gender_1, ui_widgets)
|
||||
.set(self.ids.body_type_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.gender = Gender::Male;
|
||||
self.character_body.body_type = BodyType::Male;
|
||||
}
|
||||
// Female
|
||||
Image::new(self.imgs.female)
|
||||
.w_h(68.0, 68.0)
|
||||
.right_from(self.ids.male, 16.0)
|
||||
.set(self.ids.female, ui_widgets);
|
||||
if Button::image(if let Gender::Female = self.character.gender {
|
||||
if Button::image(if let BodyType::Female = self.character_body.body_type {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -630,10 +633,10 @@ impl CharSelectionUi {
|
||||
.middle_of(self.ids.female)
|
||||
.hover_image(self.imgs.icon_border_mo)
|
||||
.press_image(self.imgs.icon_border_press)
|
||||
.set(self.ids.gender_2, ui_widgets)
|
||||
.set(self.ids.body_type_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.gender = Gender::Female;
|
||||
self.character_body.body_type = BodyType::Female;
|
||||
}
|
||||
// for alignment
|
||||
Rectangle::fill_with([458.0, 68.0], color::TRANSPARENT)
|
||||
@ -641,7 +644,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.races_bg, ui_widgets);
|
||||
// TODO: If races where in some sort of array format we could do this in a loop
|
||||
// Human
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.human_m
|
||||
} else {
|
||||
self.imgs.human_f
|
||||
@ -649,7 +652,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.mid_left_of(self.ids.races_bg)
|
||||
.set(self.ids.human, ui_widgets);
|
||||
if Button::image(if let Race::Human = self.character.race {
|
||||
if Button::image(if let Race::Human = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -660,11 +663,11 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Human;
|
||||
self.character_body.race = Race::Human;
|
||||
}
|
||||
|
||||
// Orc
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.orc_m
|
||||
} else {
|
||||
self.imgs.orc_f
|
||||
@ -672,7 +675,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.right_from(self.ids.human, 10.0)
|
||||
.set(self.ids.orc, ui_widgets);
|
||||
if Button::image(if let Race::Orc = self.character.race {
|
||||
if Button::image(if let Race::Orc = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -683,10 +686,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Orc;
|
||||
self.character_body.race = Race::Orc;
|
||||
}
|
||||
// Dwarf
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.dwarf_m
|
||||
} else {
|
||||
self.imgs.dwarf_f
|
||||
@ -694,7 +697,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.right_from(self.ids.human, 10.0 * 2.0 + 68.0)
|
||||
.set(self.ids.dwarf, ui_widgets);
|
||||
if Button::image(if let Race::Dwarf = self.character.race {
|
||||
if Button::image(if let Race::Dwarf = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -705,10 +708,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_3, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Dwarf;
|
||||
self.character_body.race = Race::Dwarf;
|
||||
}
|
||||
// Elf
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.elf_m
|
||||
} else {
|
||||
self.imgs.elf_f
|
||||
@ -716,7 +719,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.right_from(self.ids.human, 10.0 * 3.0 + 68.0 * 2.0)
|
||||
.set(self.ids.elf, ui_widgets);
|
||||
if Button::image(if let Race::Elf = self.character.race {
|
||||
if Button::image(if let Race::Elf = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -727,10 +730,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_4, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Elf;
|
||||
self.character_body.race = Race::Elf;
|
||||
}
|
||||
// Undead
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.undead_m
|
||||
} else {
|
||||
self.imgs.undead_f
|
||||
@ -738,7 +741,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.right_from(self.ids.human, 10.0 * 4.0 + 68.0 * 3.0)
|
||||
.set(self.ids.undead, ui_widgets);
|
||||
if Button::image(if let Race::Undead = self.character.race {
|
||||
if Button::image(if let Race::Undead = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -749,17 +752,17 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_5, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Undead;
|
||||
self.character_body.race = Race::Undead;
|
||||
}
|
||||
// Danari
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
Image::new(if let BodyType::Male = self.character_body.body_type {
|
||||
self.imgs.danari_m
|
||||
} else {
|
||||
self.imgs.danari_f
|
||||
})
|
||||
.right_from(self.ids.human, 10.0 * 5.0 + 68.0 * 4.0)
|
||||
.set(self.ids.danari, ui_widgets);
|
||||
if Button::image(if let Race::Danari = self.character.race {
|
||||
if Button::image(if let Race::Danari = self.character_body.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -771,7 +774,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_6, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.race = Race::Danari;
|
||||
self.character_body.race = Race::Danari;
|
||||
}
|
||||
|
||||
// Description Headline and Text
|
||||
@ -832,7 +835,7 @@ impl CharSelectionUi {
|
||||
\n\
|
||||
Outcast communities consisting of these Blessed Danari have formed all over the land.";
|
||||
|
||||
let (race_str, race_desc) = match self.character.race {
|
||||
let (race_str, race_desc) = match self.character_body.race {
|
||||
Race::Human => ("Humans", HUMAN_DESC),
|
||||
Race::Orc => ("Orcs", ORC_DESC),
|
||||
Race::Dwarf => ("Dwarves", DWARF_DESC),
|
||||
@ -872,7 +875,7 @@ impl CharSelectionUi {
|
||||
.w_h(60.0, 60.0)
|
||||
.mid_left_of(self.ids.weapon_bg)
|
||||
.set(self.ids.sword_shield, ui_widgets);
|
||||
if Button::image(if let Weapon::SwordShield = self.character.weapon {
|
||||
if Button::image(if let Weapon::SwordShield = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -883,7 +886,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::SwordShield;
|
||||
self.character_body.weapon = Weapon::SwordShield;
|
||||
}
|
||||
|
||||
// Daggers
|
||||
@ -891,7 +894,7 @@ impl CharSelectionUi {
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0)
|
||||
.set(self.ids.daggers, ui_widgets);
|
||||
if Button::image(if let Weapon::Daggers = self.character.weapon {
|
||||
if Button::image(if let Weapon::Daggers = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -902,7 +905,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Daggers;
|
||||
self.character_body.weapon = Weapon::Daggers;
|
||||
}
|
||||
|
||||
// Sword
|
||||
@ -910,7 +913,7 @@ impl CharSelectionUi {
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0 * 2.0 + 60.0 * 1.0)
|
||||
.set(self.ids.sword, ui_widgets);
|
||||
if Button::image(if let Weapon::Sword = self.character.weapon {
|
||||
if Button::image(if let Weapon::Sword = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -921,14 +924,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_3, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Sword;
|
||||
self.character_body.weapon = Weapon::Sword;
|
||||
}
|
||||
// Axe
|
||||
Image::new(self.imgs.axe)
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0 * 3.0 + 60.0 * 2.0)
|
||||
.set(self.ids.axe, ui_widgets);
|
||||
if Button::image(if let Weapon::Axe = self.character.weapon {
|
||||
if Button::image(if let Weapon::Axe = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -939,14 +942,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_4, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Axe;
|
||||
self.character_body.weapon = Weapon::Axe;
|
||||
}
|
||||
// Hammer
|
||||
Image::new(self.imgs.hammer)
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0 * 4.0 + 60.0 * 3.0)
|
||||
.set(self.ids.hammer, ui_widgets);
|
||||
if Button::image(if let Weapon::Hammer = self.character.weapon {
|
||||
if Button::image(if let Weapon::Hammer = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -957,14 +960,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_5, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Hammer;
|
||||
self.character_body.weapon = Weapon::Hammer;
|
||||
}
|
||||
// Bow
|
||||
Image::new(self.imgs.bow)
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0 * 5.0 + 60.0 * 4.0)
|
||||
.set(self.ids.bow, ui_widgets);
|
||||
if Button::image(if let Weapon::Bow = self.character.weapon {
|
||||
if Button::image(if let Weapon::Bow = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -975,14 +978,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_6, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Bow;
|
||||
self.character_body.weapon = Weapon::Bow;
|
||||
}
|
||||
// Staff
|
||||
Image::new(self.imgs.staff)
|
||||
.w_h(60.0, 60.0)
|
||||
.right_from(self.ids.sword_shield, 8.0 * 6.0 + 60.0 * 5.0)
|
||||
.set(self.ids.staff, ui_widgets);
|
||||
if Button::image(if let Weapon::Staff = self.character.weapon {
|
||||
if Button::image(if let Weapon::Staff = self.character_body.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -993,7 +996,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_7, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character.weapon = Weapon::Staff;
|
||||
self.character_body.weapon = Weapon::Staff;
|
||||
}
|
||||
|
||||
// TODO: Load these from files (or from the server???)
|
||||
@ -1005,7 +1008,7 @@ impl CharSelectionUi {
|
||||
const BOW_DESC: &str = " MISSING ";
|
||||
const STAFF_DESC: &str = " MISSING ";
|
||||
|
||||
let (weapon_str, weapon_desc) = match self.character.weapon {
|
||||
let (weapon_str, weapon_desc) = match self.character_body.weapon {
|
||||
Weapon::SwordShield => ("Sword and Shield", SWORDSHIELD_DESC),
|
||||
Weapon::Daggers => ("Daggers", DAGGERS_DESC),
|
||||
Weapon::Sword => ("Sword", SWORD_DESC),
|
||||
@ -1352,7 +1355,7 @@ impl CharSelectionUi {
|
||||
.was_clicked()
|
||||
{};
|
||||
// Beard -> Only active when "male" was chosen
|
||||
if let Gender::Male = self.character.gender {
|
||||
if let BodyType::Male = self.character_body.body_type {
|
||||
Text::new("Beard Style")
|
||||
.mid_top_with_margin_on(self.ids.hair_window, 340.0)
|
||||
.color(TEXT_COLOR)
|
||||
@ -1383,7 +1386,7 @@ impl CharSelectionUi {
|
||||
// Color -> Picker
|
||||
// Brightness -> Slider
|
||||
BodyPart::Accessories => {
|
||||
match self.character.race {
|
||||
match self.character_body.race {
|
||||
Race::Human => {
|
||||
Text::new("Head Band")
|
||||
.mid_top_with_margin_on(self.ids.accessories_window, 60.0)
|
||||
|
@ -14,7 +14,9 @@ use common::{
|
||||
assets,
|
||||
comp::{
|
||||
self,
|
||||
character::{Belt, Character, Chest, Draw, Foot, Hand, Head, Pants, Shoulder, Weapon},
|
||||
Body,
|
||||
HumanoidBody,
|
||||
actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon},
|
||||
},
|
||||
figure::Segment,
|
||||
msg,
|
||||
@ -25,7 +27,7 @@ use std::{collections::HashMap, f32};
|
||||
use vek::*;
|
||||
|
||||
pub struct FigureModelCache {
|
||||
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||
models: HashMap<HumanoidBody, (Model<FigurePipeline>, u64)>,
|
||||
}
|
||||
|
||||
impl FigureModelCache {
|
||||
@ -38,31 +40,30 @@ impl FigureModelCache {
|
||||
pub fn get_or_create_model(
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
character: Character,
|
||||
body: HumanoidBody,
|
||||
tick: u64,
|
||||
) -> &Model<FigurePipeline> {
|
||||
match self.models.get_mut(&character) {
|
||||
match self.models.get_mut(&body) {
|
||||
Some((model, last_used)) => {
|
||||
*last_used = tick;
|
||||
}
|
||||
None => {
|
||||
self.models.insert(
|
||||
character,
|
||||
body,
|
||||
(
|
||||
{
|
||||
let bone_meshes = [
|
||||
Some(Self::load_head(character.head)),
|
||||
Some(Self::load_chest(character.chest)),
|
||||
Some(Self::load_belt(character.belt)),
|
||||
Some(Self::load_pants(character.pants)),
|
||||
Some(Self::load_left_hand(character.hand)),
|
||||
Some(Self::load_right_hand(character.hand)),
|
||||
Some(Self::load_left_foot(character.foot)),
|
||||
Some(Self::load_right_foot(character.foot)),
|
||||
Some(Self::load_weapon(character.weapon)),
|
||||
Some(Self::load_left_shoulder(character.shoulder)),
|
||||
Some(Self::load_right_shoulder(character.shoulder)),
|
||||
//Some(Self::load_draw(character.draw)),
|
||||
Some(Self::load_head(body.head)),
|
||||
Some(Self::load_chest(body.chest)),
|
||||
Some(Self::load_belt(body.belt)),
|
||||
Some(Self::load_pants(body.pants)),
|
||||
Some(Self::load_left_hand(body.hand)),
|
||||
Some(Self::load_right_hand(body.hand)),
|
||||
Some(Self::load_left_foot(body.foot)),
|
||||
Some(Self::load_right_foot(body.foot)),
|
||||
Some(Self::load_weapon(body.weapon)),
|
||||
Some(Self::load_left_shoulder(body.shoulder)),
|
||||
Some(Self::load_right_shoulder(body.shoulder)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@ -89,7 +90,7 @@ impl FigureModelCache {
|
||||
}
|
||||
}
|
||||
|
||||
&self.models[&character].0
|
||||
&self.models[&body].0
|
||||
}
|
||||
|
||||
pub fn clean(&mut self, tick: u64) {
|
||||
@ -108,7 +109,7 @@ impl FigureModelCache {
|
||||
fn load_head(head: Head) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match head {
|
||||
Head::DefaultHead => "head.vox",
|
||||
Head::Default => "head.vox",
|
||||
},
|
||||
Vec3::new(-7.0, -5.5, -6.0),
|
||||
)
|
||||
@ -117,7 +118,7 @@ impl FigureModelCache {
|
||||
fn load_chest(chest: Chest) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match chest {
|
||||
Chest::DefaultChest => "chest.vox",
|
||||
Chest::Default => "chest.vox",
|
||||
},
|
||||
Vec3::new(-6.0, -3.5, 0.0),
|
||||
)
|
||||
@ -126,7 +127,7 @@ impl FigureModelCache {
|
||||
fn load_belt(belt: Belt) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match belt {
|
||||
Belt::DefaultBelt => "belt.vox",
|
||||
Belt::Default => "belt.vox",
|
||||
},
|
||||
Vec3::new(-5.0, -3.5, 0.0),
|
||||
)
|
||||
@ -135,7 +136,7 @@ impl FigureModelCache {
|
||||
fn load_pants(pants: Pants) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match pants {
|
||||
Pants::DefaultPants => "pants.vox",
|
||||
Pants::Default => "pants.vox",
|
||||
},
|
||||
Vec3::new(-5.0, -3.5, 0.0),
|
||||
)
|
||||
@ -144,7 +145,7 @@ impl FigureModelCache {
|
||||
fn load_left_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
Hand::Default => "hand.vox",
|
||||
},
|
||||
Vec3::new(2.0, 0.0, -7.0),
|
||||
)
|
||||
@ -153,7 +154,7 @@ impl FigureModelCache {
|
||||
fn load_right_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
Hand::Default => "hand.vox",
|
||||
},
|
||||
Vec3::new(2.0, 0.0, -7.0),
|
||||
)
|
||||
@ -162,7 +163,7 @@ impl FigureModelCache {
|
||||
fn load_left_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
Foot::Default => "foot.vox",
|
||||
},
|
||||
Vec3::new(2.5, -3.5, -9.0),
|
||||
)
|
||||
@ -171,7 +172,7 @@ impl FigureModelCache {
|
||||
fn load_right_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
Foot::Default => "foot.vox",
|
||||
},
|
||||
Vec3::new(2.5, -3.5, -9.0),
|
||||
)
|
||||
@ -238,42 +239,50 @@ impl FigureMgr {
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
|
||||
let time = client.state().get_time();
|
||||
let ecs = client.state().ecs();
|
||||
for (entity, pos, vel, dir, character, animation_history) in (
|
||||
for (entity, pos, vel, dir, actor, animation_history) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::phys::Pos>(),
|
||||
&ecs.read_storage::<comp::phys::Vel>(),
|
||||
&ecs.read_storage::<comp::phys::Dir>(),
|
||||
&ecs.read_storage::<comp::Character>(),
|
||||
&ecs.read_storage::<comp::Actor>(),
|
||||
&ecs.read_storage::<comp::AnimationHistory>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let state = self
|
||||
.states
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||
match actor {
|
||||
comp::Actor::Character { body, .. } => match body {
|
||||
Body::Humanoid(body) => {
|
||||
let state = self
|
||||
.states
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||
|
||||
let target_skeleton = match animation_history.current {
|
||||
comp::character::Animation::Idle => IdleAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_history.time,
|
||||
),
|
||||
comp::character::Animation::Run => RunAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
(vel.0.magnitude(), time),
|
||||
animation_history.time,
|
||||
),
|
||||
comp::character::Animation::Jump => JumpAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_history.time,
|
||||
),
|
||||
};
|
||||
let target_skeleton = match animation_history.current {
|
||||
comp::Animation::Idle => IdleAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_history.time,
|
||||
),
|
||||
comp::Animation::Run => RunAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
(vel.0.magnitude(), time),
|
||||
animation_history.time,
|
||||
),
|
||||
comp::Animation::Jump => JumpAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_history.time,
|
||||
),
|
||||
};
|
||||
|
||||
state.skeleton.interpolate(&target_skeleton);
|
||||
state.skeleton.interpolate(&target_skeleton);
|
||||
|
||||
state.update(renderer, pos.0, dir.0);
|
||||
state.update(renderer, pos.0, dir.0);
|
||||
},
|
||||
// TODO: Non-humanoid bodies
|
||||
},
|
||||
// TODO: Non-character actors
|
||||
}
|
||||
}
|
||||
|
||||
self.states
|
||||
@ -289,13 +298,17 @@ impl FigureMgr {
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
|
||||
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
|
||||
for (entity, actor) in (&ecs.entities(), &ecs.read_storage::<comp::Actor>()).join()
|
||||
{
|
||||
if let Some(state) = self.states.get(&entity) {
|
||||
let model = self
|
||||
.model_cache
|
||||
.get_or_create_model(renderer, character, tick);
|
||||
renderer.render_figure(model, globals, &state.locals(), state.bone_consts());
|
||||
match actor {
|
||||
comp::Actor::Character { body, .. } => match body {
|
||||
Body::Humanoid(body) => if let Some(state) = self.states.get(&entity) {
|
||||
let model = self.model_cache.get_or_create_model(renderer, *body, tick);
|
||||
renderer.render_figure(model, globals, &state.locals(), state.bone_consts());
|
||||
},
|
||||
// TODO: Non-humanoid bodies
|
||||
},
|
||||
// TODO: Non-character actors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user