mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement ClientStates
Former-commit-id: f6167fd6de6fd1a3309224409cac77193be982e2
This commit is contained in:
parent
802c484a38
commit
794b9cafad
@ -5,6 +5,7 @@ pub mod input;
|
||||
|
||||
// Reexports
|
||||
pub use specs::Entity as EcsEntity;
|
||||
pub use specs::join::Join;
|
||||
pub use crate::{
|
||||
error::Error,
|
||||
input::Input,
|
||||
@ -23,7 +24,7 @@ use common::{
|
||||
state::State,
|
||||
terrain::TerrainChunk,
|
||||
net::PostBox,
|
||||
msg::{ClientMsg, ServerMsg},
|
||||
msg::{ClientState, ClientMsg, ServerMsg},
|
||||
};
|
||||
|
||||
const SERVER_TIMEOUT: f64 = 20.0; // Seconds
|
||||
@ -33,14 +34,15 @@ pub enum Event {
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
client_state: ClientState,
|
||||
thread_pool: ThreadPool,
|
||||
|
||||
last_ping: f64,
|
||||
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||
pub postbox: PostBox<ClientMsg, ServerMsg>,
|
||||
|
||||
tick: u64,
|
||||
state: State,
|
||||
player: EcsEntity,
|
||||
entity: EcsEntity,
|
||||
view_distance: u64,
|
||||
|
||||
pending_chunks: HashSet<Vec3<i32>>,
|
||||
@ -55,24 +57,24 @@ impl Client {
|
||||
view_distance: u64,
|
||||
) -> Result<Self, Error> {
|
||||
|
||||
let mut client_state = ClientState::Disconnected;
|
||||
let mut postbox = PostBox::to(addr)?;
|
||||
|
||||
// Send connection request
|
||||
postbox.send_message(ClientMsg::Connect {
|
||||
player,
|
||||
});
|
||||
postbox.send_message(ClientMsg::Connect { player });
|
||||
|
||||
// Wait for handshake from server
|
||||
let (state, player) = match postbox.next_message() {
|
||||
Some(ServerMsg::Handshake { ecs_state, player_entity }) => {
|
||||
// Wait for initial sync
|
||||
let (state, player_entity) = match postbox.next_message() {
|
||||
Some(ServerMsg::InitialSync { ecs_state, player_entity_uid }) => {
|
||||
let mut state = State::from_state_package(ecs_state);
|
||||
let player_entity = state.ecs().entity_from_uid(player_entity).ok_or(Error::ServerWentMad)?;
|
||||
let player_entity = state.ecs().entity_from_uid(player_entity_uid).ok_or(Error::ServerWentMad)?;
|
||||
(state, player_entity)
|
||||
},
|
||||
_ => return Err(Error::ServerWentMad),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
client_state,
|
||||
thread_pool: threadpool::Builder::new()
|
||||
.thread_name("veloren-worker".into())
|
||||
.build(),
|
||||
@ -82,7 +84,7 @@ impl Client {
|
||||
|
||||
tick: 0,
|
||||
state,
|
||||
player,
|
||||
entity: player_entity,
|
||||
view_distance,
|
||||
|
||||
pending_chunks: HashSet::new(),
|
||||
@ -103,10 +105,10 @@ impl Client {
|
||||
#[allow(dead_code)]
|
||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||
|
||||
/// Get the player entity
|
||||
/// Get the player's entity
|
||||
#[allow(dead_code)]
|
||||
pub fn player(&self) -> EcsEntity {
|
||||
self.player
|
||||
pub fn entity(&self) -> EcsEntity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
/// Get the current tick number.
|
||||
@ -146,7 +148,7 @@ impl Client {
|
||||
println!("Chunk at {:?}", k);
|
||||
});
|
||||
|
||||
self.state.write_component(self.player, comp::Control {
|
||||
self.state.write_component(self.entity, comp::Control {
|
||||
move_dir: input.move_dir,
|
||||
});
|
||||
|
||||
@ -155,9 +157,9 @@ impl Client {
|
||||
|
||||
// Update the server about the player's physics attributes
|
||||
match (
|
||||
self.state.read_storage().get(self.player).cloned(),
|
||||
self.state.read_storage().get(self.player).cloned(),
|
||||
self.state.read_storage().get(self.player).cloned(),
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
self.state.read_storage().get(self.entity).cloned(),
|
||||
) {
|
||||
(Some(pos), Some(vel), Some(dir)) => {
|
||||
self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir });
|
||||
@ -166,14 +168,14 @@ impl Client {
|
||||
}
|
||||
|
||||
// Update the server about the player's currently playing animation and the previous one
|
||||
if let Some(animation_history) = self.state.read_storage::<comp::AnimationHistory>().get(self.player).cloned() {
|
||||
if let Some(animation_history) = self.state.read_storage::<comp::AnimationHistory>().get(self.entity).cloned() {
|
||||
if Some(animation_history.current) != animation_history.last {
|
||||
self.postbox.send_message(ClientMsg::PlayerAnimation(animation_history));
|
||||
}
|
||||
}
|
||||
|
||||
// Request chunks from the server
|
||||
if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(self.player) {
|
||||
if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(self.entity) {
|
||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
|
||||
for i in chunk_pos.x - 1..chunk_pos.x + 1 {
|
||||
@ -213,12 +215,12 @@ impl Client {
|
||||
|
||||
for msg in new_msgs {
|
||||
match msg {
|
||||
ServerMsg::Handshake { .. } => return Err(Error::ServerWentMad),
|
||||
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
|
||||
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
|
||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||
ServerMsg::Pong => {},
|
||||
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
||||
ServerMsg::SetPlayerEntity(uid) => self.player = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
|
||||
ServerMsg::SetPlayerEntity(uid) => self.entity = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
|
||||
ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
|
||||
ServerMsg::EntityPhysics { entity, pos, vel, dir } => match self.state.ecs().entity_from_uid(entity) {
|
||||
Some(entity) => {
|
||||
@ -238,6 +240,18 @@ impl Client {
|
||||
self.state.insert_chunk(key, *chunk);
|
||||
self.pending_chunks.remove(&key);
|
||||
},
|
||||
ServerMsg::StateAnswer(Ok(state)) => {
|
||||
println!("ok state: {:?}", state);
|
||||
self.client_state = state;
|
||||
},
|
||||
ServerMsg::StateAnswer(Err((error, state))) => {
|
||||
println!("err state: {:?}", state);
|
||||
self.client_state = state;
|
||||
},
|
||||
ServerMsg::ForceState { state } => {
|
||||
println!("forced state: {:?}", state);
|
||||
self.client_state = state;
|
||||
},
|
||||
}
|
||||
}
|
||||
} else if let Some(err) = self.postbox.error() {
|
||||
|
@ -1,15 +1,12 @@
|
||||
use vek::*;
|
||||
use super::ClientState;
|
||||
use crate::comp;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ClientMsg {
|
||||
Connect {
|
||||
player: comp::Player,
|
||||
|
||||
},
|
||||
Character {
|
||||
character: comp::Character,
|
||||
},
|
||||
Connect { player: comp::Player },
|
||||
Character(comp::Character),
|
||||
RequestState(ClientState),
|
||||
Ping,
|
||||
Pong,
|
||||
Chat(String),
|
||||
|
@ -3,6 +3,13 @@ pub mod server;
|
||||
pub mod client;
|
||||
|
||||
// Reexports
|
||||
pub use self::server::ServerMsg;
|
||||
pub use self::server::{ServerMsg, RequestStateError};
|
||||
pub use self::client::ClientMsg;
|
||||
pub use self::ecs_packet::EcsPacket;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientState {
|
||||
Disconnected,
|
||||
Spectator,
|
||||
Character,
|
||||
}
|
||||
|
@ -3,15 +3,25 @@ use crate::{
|
||||
comp,
|
||||
terrain::TerrainChunk,
|
||||
};
|
||||
use super::EcsPacket;
|
||||
use super::{EcsPacket, ClientState};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RequestStateError {
|
||||
Denied,
|
||||
Already,
|
||||
Impossible,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub enum ServerMsg {
|
||||
Handshake {
|
||||
ecs_state: sphynx::StatePackage<EcsPacket>,
|
||||
player_entity: u64,
|
||||
StateAnswer(Result<ClientState, (RequestStateError, ClientState)>),
|
||||
ForceState {
|
||||
state: ClientState,
|
||||
},
|
||||
InitialSync {
|
||||
ecs_state: sphynx::StatePackage<EcsPacket>,
|
||||
player_entity_uid: u64,
|
||||
},
|
||||
Shutdown,
|
||||
Ping,
|
||||
Pong,
|
||||
Chat(String),
|
||||
@ -31,4 +41,5 @@ pub enum ServerMsg {
|
||||
key: Vec3<i32>,
|
||||
chunk: Box<TerrainChunk>,
|
||||
},
|
||||
Shutdown,
|
||||
}
|
||||
|
@ -2,19 +2,13 @@ use std::collections::HashMap;
|
||||
use specs::Entity as EcsEntity;
|
||||
use common::{
|
||||
comp,
|
||||
msg::{ServerMsg, ClientMsg},
|
||||
msg::{ServerMsg, ClientMsg, ClientState},
|
||||
net::PostBox,
|
||||
};
|
||||
use crate::Error;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum ClientState {
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
pub state: ClientState,
|
||||
pub client_state: ClientState,
|
||||
pub postbox: PostBox<ServerMsg, ClientMsg>,
|
||||
pub last_ping: f64,
|
||||
}
|
||||
@ -52,7 +46,7 @@ impl Clients {
|
||||
|
||||
pub fn notify_connected(&mut self, msg: ServerMsg) {
|
||||
for client in self.clients.values_mut() {
|
||||
if client.state == ClientState::Connected {
|
||||
if client.client_state != ClientState::Disconnected {
|
||||
client.notify(msg.clone());
|
||||
}
|
||||
}
|
||||
@ -60,7 +54,7 @@ impl Clients {
|
||||
|
||||
pub fn notify_connected_except(&mut self, except_entity: EcsEntity, msg: ServerMsg) {
|
||||
for (entity, client) in self.clients.iter_mut() {
|
||||
if client.state == ClientState::Connected && *entity != except_entity {
|
||||
if client.client_state != ClientState::Disconnected && *entity != except_entity {
|
||||
client.notify(msg.clone());
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ pub mod cmd;
|
||||
// Reexports
|
||||
pub use crate::{error::Error, input::Input};
|
||||
|
||||
use crate::{client::{Client, ClientState, Clients}, cmd::CHAT_COMMANDS};
|
||||
use crate::{client::{Client, Clients}, cmd::CHAT_COMMANDS};
|
||||
use common::{
|
||||
comp,
|
||||
msg::{ClientMsg, ServerMsg},
|
||||
msg::{ClientState, ClientMsg, ServerMsg, RequestStateError},
|
||||
net::PostOffice,
|
||||
state::{State, Uid},
|
||||
terrain::TerrainChunk,
|
||||
@ -115,7 +115,7 @@ impl Server {
|
||||
.with(character)
|
||||
}
|
||||
|
||||
pub fn create_player_character(state: &mut State, entity: EcsEntity, character: comp::Character) {
|
||||
pub fn create_player_character(state: &mut State, entity: EcsEntity, client: &mut Client, character: comp::Character) {
|
||||
state.write_component(entity, character);
|
||||
state.write_component(entity, comp::phys::Pos(Vec3::zero()));
|
||||
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
@ -128,6 +128,10 @@ impl Server {
|
||||
last: None,
|
||||
current: Animation::Idle
|
||||
});
|
||||
|
||||
// Tell the client his request was successful
|
||||
client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character)));
|
||||
client.client_state = ClientState::Character;
|
||||
}
|
||||
|
||||
/// Execute a single server tick, handle input and update the game state by the given duration
|
||||
@ -171,10 +175,7 @@ impl Server {
|
||||
for (entity, player, pos) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&self
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -216,7 +217,7 @@ impl Server {
|
||||
self.clients.add(
|
||||
entity,
|
||||
Client {
|
||||
state: ClientState::Connecting,
|
||||
client_state: ClientState::Disconnected,
|
||||
postbox,
|
||||
last_ping: self.state.get_time(),
|
||||
},
|
||||
@ -247,27 +248,62 @@ impl Server {
|
||||
|
||||
// Process incoming messages
|
||||
for msg in new_msgs {
|
||||
match client.state {
|
||||
ClientState::Connecting => match msg {
|
||||
ClientMsg::Connect { player } => {
|
||||
Self::initialize_client(state, entity, client, player);
|
||||
match msg {
|
||||
ClientMsg::RequestState(requested_state) => match requested_state {
|
||||
ClientState::Spectator => match client.client_state {
|
||||
// Use ClientMsg::Connect instead
|
||||
ClientState::Disconnected => {},
|
||||
ClientState::Spectator => {
|
||||
// Already
|
||||
client.postbox.send_message(ServerMsg::StateAnswer(
|
||||
Err((RequestStateError::Already, ClientState::Spectator))));
|
||||
},
|
||||
ClientState::Character => {
|
||||
// Always allow
|
||||
client.postbox.send_message(ServerMsg::StateAnswer(
|
||||
Ok(ClientState::Spectator)));
|
||||
},
|
||||
},
|
||||
// Use ClientMsg::Character instead
|
||||
ClientState::Character => { unimplemented!("TODO: Check for previously used character"); },
|
||||
ClientState::Disconnected => disconnect = true,
|
||||
},
|
||||
ClientMsg::Connect { player } => match client.client_state {
|
||||
ClientState::Disconnected => Self::initialize_client(state, entity, client, player),
|
||||
_ => {},
|
||||
},
|
||||
ClientMsg::Character(character) => match client.client_state {
|
||||
ClientState::Spectator => Self::create_player_character(state, entity, client, character),
|
||||
// Currently only possible from spectator
|
||||
_ => disconnect = true,
|
||||
},
|
||||
|
||||
// Always possible
|
||||
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
|
||||
ClientMsg::Pong => {}
|
||||
ClientMsg::Disconnect => disconnect = true,
|
||||
|
||||
ClientMsg::Chat(msg) => match client.client_state {
|
||||
ClientState::Disconnected => {}
|
||||
_ => new_chat_msgs.push((entity, msg)),
|
||||
},
|
||||
|
||||
ClientMsg::PlayerAnimation(animation_history) => match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, animation_history);
|
||||
}
|
||||
_ => disconnect = true,
|
||||
},
|
||||
ClientState::Connected => match msg {
|
||||
ClientMsg::Connect { .. } => disconnect = true, // Not allowed when already connected
|
||||
ClientMsg::Disconnect => disconnect = true,
|
||||
ClientMsg::Character { character } => Self::create_player_character(state, entity, character),
|
||||
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
|
||||
ClientMsg::Pong => {}
|
||||
ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)),
|
||||
ClientMsg::PlayerAnimation(animation_history) => state.write_component(entity, animation_history),
|
||||
ClientMsg::PlayerPhysics { pos, vel, dir } => {
|
||||
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, pos);
|
||||
state.write_component(entity, vel);
|
||||
state.write_component(entity, dir);
|
||||
}
|
||||
ClientMsg::TerrainChunkRequest { key } => {
|
||||
},
|
||||
_ => disconnect = true,
|
||||
},
|
||||
ClientMsg::TerrainChunkRequest { key } => match client.client_state {
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
match state.terrain().get_key(key) {
|
||||
Some(chunk) => {} /*client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
@ -275,8 +311,9 @@ impl Server {
|
||||
}),*/
|
||||
None => requested_chunks.push(key),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
ClientState::Disconnected => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout
|
||||
@ -290,7 +327,10 @@ impl Server {
|
||||
}
|
||||
|
||||
if disconnect {
|
||||
println!("Someone disconnected!");
|
||||
disconnected_clients.push(entity);
|
||||
client.postbox.send_message(ServerMsg::StateAnswer(
|
||||
Err((RequestStateError::Impossible, ClientState::Disconnected))));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -345,13 +385,11 @@ impl Server {
|
||||
// Save player metadata (for example the username)
|
||||
state.write_component(entity, player);
|
||||
|
||||
client.state = ClientState::Connected;
|
||||
|
||||
// Return a handshake with the state of the current world
|
||||
// Return the state of the current world
|
||||
// (All components Sphynx tracks)
|
||||
client.notify(ServerMsg::Handshake {
|
||||
client.notify(ServerMsg::InitialSync {
|
||||
ecs_state: state.ecs().gen_state_package(),
|
||||
player_entity: state
|
||||
player_entity_uid: state
|
||||
.ecs()
|
||||
.uid_from_entity(entity)
|
||||
.unwrap()
|
||||
@ -370,6 +408,10 @@ impl Server {
|
||||
animation_history: animation_history,
|
||||
});
|
||||
}
|
||||
|
||||
// Tell the client his request was successful
|
||||
client.notify(ServerMsg::StateAnswer(Ok(ClientState::Spectator)));
|
||||
client.client_state = ClientState::Spectator;
|
||||
}
|
||||
|
||||
/// Sync client states with the most up to date information
|
||||
|
@ -6,7 +6,10 @@ use crate::{
|
||||
GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::clock::Clock;
|
||||
use common::{
|
||||
clock::Clock,
|
||||
msg::ClientMsg,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use ui::CharSelectionUi;
|
||||
use vek::*;
|
||||
@ -67,9 +70,10 @@ impl PlayState for CharSelectionState {
|
||||
global_state.singleplayer = None;
|
||||
return PlayStateResult::Pop;
|
||||
},
|
||||
ui::Event::Play => return PlayStateResult::Switch(
|
||||
ui::Event::Play => {
|
||||
self.client.borrow_mut().postbox.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
||||
Box::new(SessionState::new(&mut global_state.window, self.client.clone()))
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
use common::{
|
||||
assets,
|
||||
comp::character::{
|
||||
self,
|
||||
Character,
|
||||
Race,
|
||||
Gender,
|
||||
Head,
|
||||
@ -353,17 +353,9 @@ pub struct CharSelectionUi {
|
||||
font_opensans: FontId,
|
||||
character_creation: bool,
|
||||
selected_char_no: Option<i32>,
|
||||
race: Race,
|
||||
gender: Gender,
|
||||
head: Head,
|
||||
chest: Chest,
|
||||
belt: Belt,
|
||||
pants: Pants,
|
||||
hand: Hand,
|
||||
foot: Foot,
|
||||
weapon: Weapon,
|
||||
creation_state: CreationState,
|
||||
character_name: String,
|
||||
pub character: Character,
|
||||
creation_state: CreationState,
|
||||
}
|
||||
|
||||
impl CharSelectionUi {
|
||||
@ -396,15 +388,7 @@ impl CharSelectionUi {
|
||||
character_creation: false,
|
||||
selected_char_no: None,
|
||||
character_name: "Character Name".to_string(),
|
||||
race: Race::Human,
|
||||
gender: Gender::Male,
|
||||
head: Head::DefaultHead,
|
||||
chest: Chest::DefaultChest,
|
||||
belt: Belt::DefaultBelt,
|
||||
pants: Pants::DefaultPants,
|
||||
hand: Hand::DefaultHand,
|
||||
foot: Foot::DefaultFoot,
|
||||
weapon: Weapon::Sword,
|
||||
character: Character::random(),
|
||||
creation_state: CreationState::Race,
|
||||
}
|
||||
}
|
||||
@ -711,7 +695,7 @@ impl CharSelectionUi {
|
||||
.w_h(68.0, 68.0)
|
||||
.mid_left_of(self.ids.gender_bg)
|
||||
.set(self.ids.male, ui_widgets);
|
||||
if Button::image(if let Gender::Male = self.gender {
|
||||
if Button::image(if let Gender::Male = self.character.gender {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -722,14 +706,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.gender_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.gender = Gender::Male;
|
||||
self.character.gender = Gender::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.gender {
|
||||
if Button::image(if let Gender::Female = self.character.gender {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -740,7 +724,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.gender_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.gender = Gender::Female;
|
||||
self.character.gender = Gender::Female;
|
||||
}
|
||||
// for alignment
|
||||
Rectangle::fill_with([458.0, 68.0], color::TRANSPARENT)
|
||||
@ -748,7 +732,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.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
self.imgs.human_m
|
||||
} else {
|
||||
self.imgs.human_f
|
||||
@ -756,7 +740,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.race {
|
||||
if Button::image(if let Race::Human = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -767,11 +751,11 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Human;
|
||||
self.character.race = Race::Human;
|
||||
}
|
||||
|
||||
// Orc
|
||||
Image::new(if let Gender::Male = self.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
self.imgs.orc_m
|
||||
} else {
|
||||
self.imgs.orc_f
|
||||
@ -779,7 +763,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.race {
|
||||
if Button::image(if let Race::Orc = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -790,10 +774,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Orc;
|
||||
self.character.race = Race::Orc;
|
||||
}
|
||||
// Dwarf
|
||||
Image::new(if let Gender::Male = self.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
self.imgs.dwarf_m
|
||||
} else {
|
||||
self.imgs.dwarf_f
|
||||
@ -801,7 +785,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.race {
|
||||
if Button::image(if let Race::Dwarf = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -812,10 +796,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_3, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Dwarf;
|
||||
self.character.race = Race::Dwarf;
|
||||
}
|
||||
// Elf
|
||||
Image::new(if let Gender::Male = self.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
self.imgs.elf_m
|
||||
} else {
|
||||
self.imgs.elf_f
|
||||
@ -823,7 +807,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.race {
|
||||
if Button::image(if let Race::Elf = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -834,10 +818,10 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_4, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Elf;
|
||||
self.character.race = Race::Elf;
|
||||
}
|
||||
// Undead
|
||||
Image::new(if let Gender::Male = self.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
self.imgs.undead_m
|
||||
} else {
|
||||
self.imgs.undead_f
|
||||
@ -845,7 +829,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.race {
|
||||
if Button::image(if let Race::Undead = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -856,17 +840,17 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_5, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Undead;
|
||||
self.character.race = Race::Undead;
|
||||
}
|
||||
// Danari
|
||||
Image::new(if let Gender::Male = self.gender {
|
||||
Image::new(if let Gender::Male = self.character.gender {
|
||||
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.race {
|
||||
if Button::image(if let Race::Danari = self.character.race {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -878,7 +862,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.race_6, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.race = Race::Danari;
|
||||
self.character.race = Race::Danari;
|
||||
}
|
||||
|
||||
// Description Headline and Text
|
||||
@ -939,7 +923,7 @@ impl CharSelectionUi {
|
||||
\n\
|
||||
Outcast communities consisting of these Blessed Danari have formed all over the land.";
|
||||
|
||||
let (race_str, race_desc) = match self.race {
|
||||
let (race_str, race_desc) = match self.character.race {
|
||||
Race::Human => ("Humans", HUMAN_DESC),
|
||||
Race::Orc => ("Orcs", ORC_DESC),
|
||||
Race::Dwarf => ("Dwarves", DWARF_DESC),
|
||||
@ -979,7 +963,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.weapon {
|
||||
if Button::image(if let Weapon::SwordShield = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -990,7 +974,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_1, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::SwordShield;
|
||||
self.character.weapon = Weapon::SwordShield;
|
||||
}
|
||||
|
||||
// Daggers
|
||||
@ -998,7 +982,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.weapon {
|
||||
if Button::image(if let Weapon::Daggers = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1009,7 +993,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_2, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Daggers;
|
||||
self.character.weapon = Weapon::Daggers;
|
||||
}
|
||||
|
||||
// Sword
|
||||
@ -1017,7 +1001,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.weapon {
|
||||
if Button::image(if let Weapon::Sword = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1028,14 +1012,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_3, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Sword;
|
||||
self.character.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.weapon {
|
||||
if Button::image(if let Weapon::Axe = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1046,14 +1030,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_4, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Axe;
|
||||
self.character.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.weapon {
|
||||
if Button::image(if let Weapon::Hammer = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1064,14 +1048,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_5, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Hammer;
|
||||
self.character.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.weapon {
|
||||
if Button::image(if let Weapon::Bow = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1082,14 +1066,14 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_6, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Bow;
|
||||
self.character.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.weapon {
|
||||
if Button::image(if let Weapon::Staff = self.character.weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -1100,7 +1084,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.weapon_7, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.weapon = Weapon::Staff;
|
||||
self.character.weapon = Weapon::Staff;
|
||||
}
|
||||
|
||||
// TODO: Load these from files (or from the server???)
|
||||
@ -1112,7 +1096,7 @@ impl CharSelectionUi {
|
||||
const BOW_DESC: &str = " MISSING ";
|
||||
const STAFF_DESC: &str = " MISSING ";
|
||||
|
||||
let (weapon_str, weapon_desc) = match self.weapon {
|
||||
let (weapon_str, weapon_desc) = match self.character.weapon {
|
||||
Weapon::SwordShield => ("Sword and Shield", SWORDSHIELD_DESC),
|
||||
Weapon::Daggers => ("Daggers", DAGGERS_DESC),
|
||||
Weapon::Sword => ("Sword", SWORD_DESC),
|
||||
@ -1459,7 +1443,7 @@ impl CharSelectionUi {
|
||||
.was_clicked()
|
||||
{};
|
||||
// Beard -> Only active when "male" was chosen
|
||||
if let Gender::Male = self.gender {
|
||||
if let Gender::Male = self.character.gender {
|
||||
Text::new("Beard Style")
|
||||
.mid_top_with_margin_on(self.ids.hair_window, 340.0)
|
||||
.color(TEXT_COLOR)
|
||||
@ -1490,7 +1474,7 @@ impl CharSelectionUi {
|
||||
// Color -> Picker
|
||||
// Brightness -> Slider
|
||||
BodyPart::Accessories => {
|
||||
match self.race {
|
||||
match self.character.race {
|
||||
Race::Human => {
|
||||
Text::new("Head Band")
|
||||
.mid_top_with_margin_on(self.ids.accessories_window, 60.0)
|
||||
|
@ -112,7 +112,7 @@ impl Scene {
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.get(client.player())
|
||||
.get(client.entity())
|
||||
.map(|pos| pos.0)
|
||||
.unwrap_or(Vec3::zero());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user