From b3e4ca0a5d9eebecbe25b8029d6fb4a8258f05a3 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Fri, 17 May 2019 22:47:58 +0200 Subject: [PATCH 01/34] Implement killing Change animation history to animation Add attack input event Implement killing with ecs systems for damage and death Sync attack properly Sync deaths Former-commit-id: 72b5be7d65d9d3fcbef50d4836a6f06ec218d69e --- client/src/input.rs | 1 + client/src/lib.rs | 122 ++++++++++++++++--------- common/src/comp/action.rs | 20 ++++ common/src/comp/actor.rs | 30 ------ common/src/comp/animation.rs | 32 +++++++ common/src/comp/mod.rs | 9 +- common/src/comp/phys.rs | 2 +- common/src/comp/stats.rs | 13 ++- common/src/msg/client.rs | 3 +- common/src/msg/server.rs | 2 +- common/src/state.rs | 4 +- common/src/sys/action.rs | 42 +++++++++ common/src/sys/anim.rs | 22 ----- common/src/sys/animation.rs | 25 +++++ common/src/sys/control.rs | 30 +++--- common/src/sys/mod.rs | 11 ++- common/src/sys/stats.rs | 28 ++++++ server/src/lib.rs | 82 ++++++++++------- voxygen/src/menu/char_selection/mod.rs | 11 +-- voxygen/src/scene/figure.rs | 22 ++--- voxygen/src/session.rs | 9 +- voxygen/src/window.rs | 8 +- 22 files changed, 351 insertions(+), 177 deletions(-) create mode 100644 common/src/comp/action.rs create mode 100644 common/src/comp/animation.rs create mode 100644 common/src/sys/action.rs delete mode 100644 common/src/sys/anim.rs create mode 100644 common/src/sys/animation.rs create mode 100644 common/src/sys/stats.rs diff --git a/client/src/input.rs b/client/src/input.rs index a274697e29..d93ca202a0 100644 --- a/client/src/input.rs +++ b/client/src/input.rs @@ -2,6 +2,7 @@ use vek::*; pub enum InputEvent { Jump, + AttackStarted, } pub struct Input { diff --git a/client/src/lib.rs b/client/src/lib.rs index be69fc5279..48ec3880bf 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -38,7 +38,7 @@ pub struct Client { thread_pool: ThreadPool, last_ping: f64, - pub postbox: PostBox, + postbox: PostBox, last_server_ping: Instant, last_ping_delta: f64, @@ -59,7 +59,7 @@ impl Client { let mut postbox = PostBox::to(addr)?; // Wait for initial sync - let (state, entity) = match postbox.next_message() { + let (mut state, entity) = match postbox.next_message() { Some(ServerMsg::InitialSync { ecs_state, entity_uid, @@ -74,6 +74,9 @@ impl Client { _ => return Err(Error::ServerWentMad), }; + // Initialize ecs components the client has control over + state.write_component(entity, comp::Actions::new()); + Ok(Self { client_state, thread_pool: threadpool::Builder::new() @@ -99,6 +102,11 @@ impl Client { self.postbox.send_message(ClientMsg::Register { player }); } + pub fn request_character(&mut self, name: String, body: comp::Body) { + self.postbox + .send_message(ClientMsg::Character { name, body }); + } + pub fn set_view_distance(&mut self, view_distance: u32) { self.view_distance = Some(view_distance.max(5).min(25)); self.postbox @@ -157,17 +165,40 @@ impl Client { // approximate order of things. Please update it as this code changes. // // 1) Collect input from the frontend, apply input effects to the state of the game - // 2) Go through any events (timer-driven or otherwise) that need handling and apply them + // 2) Handle messages from the server + // 3) Go through any events (timer-driven or otherwise) that need handling and apply them // to the state of the game - // 3) Perform a single LocalState tick (i.e: update the world and entities in the world) - // 4) Go through the terrain update queue and apply all changes to the terrain - // 5) Finish the tick, passing control of the main thread back to the frontend + // 4) Perform a single LocalState tick (i.e: update the world and entities in the world) + // 5) Go through the terrain update queue and apply all changes to the terrain + // 6) Sync information to the server + // 7) Finish the tick, passing control of the main thread back to the frontend - // Build up a list of events for this frame, to be passed to the frontend. - let mut frontend_events = Vec::new(); + // 1) Handle input from frontend. + for event in input.events { + match event { + InputEvent::AttackStarted => { + self.state + .ecs_mut() + .write_storage::() + .get_mut(self.entity) + .unwrap() // We initialized it in the constructor + .0 + .push(comp::Action::Attack); + } + _ => {} + } + } - // Handle new messages from the server. - frontend_events.append(&mut self.handle_new_messages()?); + // Tell the server about the actions. + if let Some(actions) = self + .state + .ecs() + .read_storage::() + .get(self.entity) + { + self.postbox + .send_message(ClientMsg::PlayerActions(actions.clone())); + } // Pass character control from frontend input to the player's entity. // TODO: Only do this if the entity already has a Control component! @@ -180,35 +211,18 @@ impl Client { }, ); - // Tick the client's LocalState (step 3). + // 2) Build up a list of events for this frame, to be passed to the frontend. + let mut frontend_events = Vec::new(); + + // Handle new messages from the server. + frontend_events.append(&mut self.handle_new_messages()?); + + // 3) + + // 4) Tick the client's LocalState self.state.tick(dt); - // Update the server about the player's physics attributes. - match ( - 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 }); - } - _ => {} - } - - // Update the server about the player's currently playing animation and the previous one. - if let Some(animation_history) = self - .state - .read_storage::() - .get(self.entity) - .cloned() - { - if Some(animation_history.current) != animation_history.last { - self.postbox - .send_message(ClientMsg::PlayerAnimation(animation_history)); - } - } - + // 5) Terrain let pos = self .state .read_storage::() @@ -259,13 +273,39 @@ impl Client { .retain(|_, created| now.duration_since(*created) < Duration::from_secs(10)); } - // send a ping to the server once every second + // Send a ping to the server once every second if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) { self.postbox.send_message(ClientMsg::Ping); self.last_server_ping = Instant::now(); } - // Finish the tick, pass control back to the frontend (step 6). + // 6) Update the server about the player's physics attributes. + match ( + 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 }); + } + _ => {} + } + + // Update the server about the player's current animation. + if let Some(mut animation_info) = self + .state + .ecs_mut() + .write_storage::() + .get_mut(self.entity) + { + if animation_info.changed { + self.postbox + .send_message(ClientMsg::PlayerAnimation(animation_info.clone())); + } + } + + // 7) Finish the tick, pass control back to the frontend. self.tick += 1; Ok(frontend_events) } @@ -319,10 +359,10 @@ impl Client { }, ServerMsg::EntityAnimation { entity, - animation_history, + animation_info, } => match self.state.ecs().entity_from_uid(entity) { Some(entity) => { - self.state.write_component(entity, animation_history); + self.state.write_component(entity, animation_info); } None => {} }, diff --git a/common/src/comp/action.rs b/common/src/comp/action.rs new file mode 100644 index 0000000000..7dfb18f9f3 --- /dev/null +++ b/common/src/comp/action.rs @@ -0,0 +1,20 @@ +use specs::{Component, FlaggedStorage, VecStorage}; +use vek::*; + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Action { + Attack, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Actions(pub Vec); + +impl Actions { + pub fn new() -> Self { + Self(Vec::new()) + } +} + +impl Component for Actions { + type Storage = FlaggedStorage>; +} diff --git a/common/src/comp/actor.rs b/common/src/comp/actor.rs index f17a9f9262..60cf6941e7 100644 --- a/common/src/comp/actor.rs +++ b/common/src/comp/actor.rs @@ -229,33 +229,3 @@ pub enum Actor { impl Component for Actor { type Storage = FlaggedStorage>; } - -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] -pub struct AnimationHistory { - pub last: Option, - pub current: Animation, - pub time: f64, -} - -impl AnimationHistory { - pub fn new(animation: Animation) -> Self { - Self { - last: None, - current: animation, - time: 0.0, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum Animation { - Idle, - Run, - Jump, - Gliding, - Attack, -} - -impl Component for AnimationHistory { - type Storage = FlaggedStorage>; -} diff --git a/common/src/comp/animation.rs b/common/src/comp/animation.rs new file mode 100644 index 0000000000..72c8bc56c4 --- /dev/null +++ b/common/src/comp/animation.rs @@ -0,0 +1,32 @@ +use specs::{Component, FlaggedStorage, VecStorage}; +use vek::*; + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Animation { + Idle, + Run, + Jump, + Gliding, + Attack, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub struct AnimationInfo { + pub animation: Animation, + pub time: f64, + pub changed: bool, +} + +impl AnimationInfo { + pub fn new() -> Self { + Self { + animation: Animation::Idle, + time: 0.0, + changed: true, + } + } +} + +impl Component for AnimationInfo { + type Storage = FlaggedStorage>; +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index a75e09c083..f1e8ec8423 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,16 +1,21 @@ +pub mod action; pub mod actor; pub mod agent; +pub mod animation; pub mod phys; pub mod player; pub mod stats; // Reexports +pub use action::Action; +pub use action::Actions; pub use actor::Actor; -pub use actor::Animation; -pub use actor::AnimationHistory; pub use actor::Body; pub use actor::HumanoidBody; pub use actor::QuadrupedBody; pub use agent::{Agent, Control}; +pub use animation::Animation; +pub use animation::AnimationInfo; pub use player::Player; +pub use stats::Dying; pub use stats::Stats; diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs index cb9765b6c1..8bfd9150bc 100644 --- a/common/src/comp/phys.rs +++ b/common/src/comp/phys.rs @@ -28,7 +28,7 @@ impl Component for Dir { type Storage = VecStorage; } -// Update +// ForceUpdate #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct ForceUpdate; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 3b6e263af2..def733e988 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -1,6 +1,6 @@ -use specs::{Component, FlaggedStorage, VecStorage}; +use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Health { pub current: u32, pub maximum: u32, @@ -14,7 +14,7 @@ impl Health { } } -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Stats { pub hp: Health, pub xp: u32, @@ -36,3 +36,10 @@ impl Default for Stats { impl Component for Stats { type Storage = FlaggedStorage>; } + +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] +pub struct Dying; + +impl Component for Dying { + type Storage = NullStorage; +} diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index 2c3d2bbc3f..91e5a09373 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -16,7 +16,8 @@ pub enum ClientMsg { Ping, Pong, Chat(String), - PlayerAnimation(comp::AnimationHistory), + PlayerActions(comp::Actions), + PlayerAnimation(comp::AnimationInfo), PlayerPhysics { pos: comp::phys::Pos, vel: comp::phys::Vel, diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 4a315dc5b7..379f65cddf 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -31,7 +31,7 @@ pub enum ServerMsg { }, EntityAnimation { entity: u64, - animation_history: comp::AnimationHistory, + animation_info: comp::AnimationInfo, }, TerrainChunkUpdate { key: Vec2, diff --git a/common/src/state.rs b/common/src/state.rs index ca5b3d87f4..e42e78ed9a 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -108,7 +108,9 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs new file mode 100644 index 0000000000..e82bb67d95 --- /dev/null +++ b/common/src/sys/action.rs @@ -0,0 +1,42 @@ +// Library +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; +use vek::*; + +// Crate +use crate::{ + comp::{phys::Pos, Action, Actions, Control, Stats}, + state::DeltaTime, +}; + +// Basic ECS AI agent system +pub struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + Read<'a, DeltaTime>, + WriteStorage<'a, Actions>, + ReadStorage<'a, Pos>, + WriteStorage<'a, Stats>, + ); + + fn run(&mut self, (entities, dt, mut actions, positions, mut stats): Self::SystemData) { + for (a, mut actions_a, pos_a) in (&entities, &mut actions, &positions).join() { + for event in actions_a.0.drain(..) { + match event { + Action::Attack => { + for (b, pos_b, stat_b) in (&entities, &positions, &mut stats).join() { + if a == b { + continue; + } + if pos_a.0.distance_squared(pos_b.0) < 50.0 { + &mut stat_b.hp.change_by(-60, 0.0); // TODO: variable damage and current time + &stat_b.hp; + } + } + } + } + } + } + } +} diff --git a/common/src/sys/anim.rs b/common/src/sys/anim.rs deleted file mode 100644 index 569fa5a459..0000000000 --- a/common/src/sys/anim.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Library -use specs::{Join, Read, ReadStorage, System, WriteStorage}; -use vek::*; - -// Crate -use crate::{ - comp::{phys::Pos, AnimationHistory, Control}, - state::DeltaTime, -}; - -// Basic ECS AI agent system -pub struct Sys; - -impl<'a> System<'a> for Sys { - type SystemData = (Read<'a, DeltaTime>, WriteStorage<'a, AnimationHistory>); - - fn run(&mut self, (dt, mut anim_history): Self::SystemData) { - for (mut anim_history) in (&mut anim_history).join() { - anim_history.time += dt.0 as f64; - } - } -} diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs new file mode 100644 index 0000000000..0978dd0c9c --- /dev/null +++ b/common/src/sys/animation.rs @@ -0,0 +1,25 @@ +// Library +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; +use vek::*; + +// Crate +use crate::{ + comp::{phys::Pos, ActionState, ActionEvent, Control, Stats}, + state::DeltaTime, +}; + +// Basic ECS AI agent system +pub struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = ( + Read<'a, DeltaTime>, + WriteStorage<'a, ActionState>, + ); + + fn run(&mut self, (dt, mut action_states): Self::SystemData) { + for (dt, mut animation) in (dt, &mut animation).join() { + animation.time += dt.0 as f64; + } + } +} diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs index 0fa60fe0d0..83de8436cc 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/control.rs @@ -6,7 +6,7 @@ use vek::*; use crate::{ comp::{ phys::{Dir, Pos, Vel}, - Animation, AnimationHistory, Control, + Animation, AnimationInfo, Control, }, state::DeltaTime, terrain::TerrainMap, @@ -24,13 +24,13 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Dir>, - WriteStorage<'a, AnimationHistory>, + WriteStorage<'a, AnimationInfo>, ReadStorage<'a, Control>, ); fn run( &mut self, - (terrain, dt, entities, pos, mut vels, mut dirs, mut anims, controls): Self::SystemData, + (terrain, dt, entities, pos, mut vels, mut dirs, mut animation_infos, controls): Self::SystemData, ) { for (entity, pos, mut vel, mut dir, control) in (&entities, &pos, &mut vels, &mut dirs, &controls).join() @@ -94,22 +94,18 @@ impl<'a> System<'a> for Sys { Animation::Jump }; - let last_history = anims.get_mut(entity).cloned(); + let last = animation_infos + .get_mut(entity) + .cloned() + .unwrap_or(AnimationInfo::new()); + let changed = last.animation != animation; - let time = if let Some((true, time)) = - last_history.map(|last| (last.current == animation, last.time)) - { - time - } else { - 0.0 - }; - - anims.insert( + animation_infos.insert( entity, - AnimationHistory { - last: last_history.map(|last| last.current), - current: animation, - time, + AnimationInfo { + animation, + time: if changed { 0.0 } else { last.time }, + changed, }, ); } diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index 85427a1e59..cc242e6cbf 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -1,7 +1,8 @@ +pub mod action; pub mod agent; -pub mod anim; pub mod control; pub mod phys; +mod stats; // External use specs::DispatcherBuilder; @@ -11,10 +12,16 @@ const AGENT_SYS: &str = "agent_sys"; const CONTROL_SYS: &str = "control_sys"; const PHYS_SYS: &str = "phys_sys"; const ANIM_SYS: &str = "anim_sys"; +const MOVEMENT_SYS: &str = "movement_sys"; +const ACTION_SYS: &str = "action_sys"; +const STATS_SYS: &str = "stats_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(phys::Sys, PHYS_SYS, &[]); - dispatch_builder.add(control::Sys, CONTROL_SYS, &["phys_sys"]); + dispatch_builder.add(control::Sys, CONTROL_SYS, &[PHYS_SYS]); dispatch_builder.add(anim::Sys, ANIM_SYS, &[]); + dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); + dispatch_builder.add(action::Sys, ACTION_SYS, &[]); + dispatch_builder.add(stats::Sys, STATS_SYS, &[ACTION_SYS]); } diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs new file mode 100644 index 0000000000..e979b5e1a4 --- /dev/null +++ b/common/src/sys/stats.rs @@ -0,0 +1,28 @@ +// Library +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; +use vek::*; + +// Crate +use crate::{ + comp::{Control, Dying, Stats}, + state::DeltaTime, +}; + +// Basic ECS AI agent system +pub struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + ReadStorage<'a, Stats>, + WriteStorage<'a, Dying>, + ); + + fn run(&mut self, (entities, stats, mut dyings): Self::SystemData) { + for (entity, stat) in (&entities, &stats).join() { + if stat.hp.current == 0 { + dyings.insert(entity, Dying); + } + } + } +} diff --git a/server/src/lib.rs b/server/src/lib.rs index 3b98f194ce..c9bb50ed3c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -134,7 +134,7 @@ impl Server { .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(comp::Animation::Idle)) + .with(comp::Actions::new()) .with(comp::Actor::Character { name, body }) .with(comp::Stats::default()) } @@ -156,7 +156,10 @@ impl Server { state.write_component(entity, comp::phys::ForceUpdate); // Set initial animation. - state.write_component(entity, comp::AnimationHistory::new(comp::Animation::Idle)); + state.write_component(entity, comp::AnimationInfo::new()); + + // Set initial actions (none). + state.write_component(entity, comp::Actions::new()); // Tell the client its request was successful. client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); @@ -180,7 +183,7 @@ impl Server { // 6) Send relevant state updates to all clients // 7) Finish the tick, passing control of the main thread back to the frontend - // Build up a list of events for this frame, to be passed to the frontend. + // 1) Build up a list of events for this frame, to be passed to the frontend. let mut frontend_events = Vec::new(); // If networking has problems, handle them. @@ -188,19 +191,19 @@ impl Server { return Err(err.into()); } - // Handle new client connections (step 2). - frontend_events.append(&mut self.handle_new_connections()?); + // 2) - // Handle new messages from clients + // 3) Handle inputs from clients + frontend_events.append(&mut self.handle_new_connections()?); frontend_events.append(&mut self.handle_new_messages()?); - // Tick the client's LocalState (step 3). + // 4) Tick the client's LocalState. self.state.tick(dt); // Tick the world self.world.tick(dt); - // Fetch any generated `TerrainChunk`s and insert them into the terrain. + // 5) Fetch any generated `TerrainChunk`s and insert them into the terrain. // Also, send the chunk data to anybody that is close by. if let Ok((key, chunk)) = self.chunk_rx.try_recv() { // Send the chunk to all nearby players. @@ -261,10 +264,10 @@ impl Server { self.state.remove_chunk(key); } - // Synchronise clients with the new state of the world. + // 6) Synchronise clients with the new state of the world. self.sync_clients(); - // Finish the tick, pass control back to the frontend (step 6). + // 7) Finish the tick, pass control back to the frontend. Ok(frontend_events) } @@ -389,10 +392,19 @@ impl Server { | ClientState::Spectator | ClientState::Character => new_chat_msgs.push((entity, msg)), }, - ClientMsg::PlayerAnimation(animation_history) => { + ClientMsg::PlayerActions(mut actions) => { + state + .ecs_mut() + .write_storage::() + .get_mut(entity) + .map(|s| { + s.0.append(&mut actions.0); + }); + } + ClientMsg::PlayerAnimation(animation_info) => { match client.client_state { ClientState::Character => { - state.write_component(entity, animation_history) + state.write_component(entity, animation_info) } // Only characters can send animations. _ => client.error_state(RequestStateError::Impossible), @@ -492,17 +504,17 @@ impl Server { state.write_component(entity, player); // Sync logical information other players have authority over, not the server. - for (other_entity, &uid, &animation_history) in ( + for (other_entity, &uid, &animation_info) in ( &state.ecs().entities(), &state.ecs().read_storage::(), - &state.ecs().read_storage::(), + &state.ecs().read_storage::(), ) .join() { - // AnimationHistory + // Animation client.postbox.send_message(ServerMsg::EntityAnimation { entity: uid.into(), - animation_history: animation_history, + animation_info: animation_info, }); } @@ -543,36 +555,36 @@ impl Server { } } - // Sync animation states. - for (entity, &uid, &animation_history) in ( + // Sync animation. + for (entity, &uid, &animation_info) in ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), - &self.state.ecs().read_storage::(), + &self.state.ecs().read_storage::(), ) .join() { - // Check if we need to sync. - if Some(animation_history.current) == animation_history.last { - continue; + if animation_info.changed { + self.clients.notify_ingame_except( + entity, + ServerMsg::EntityAnimation { + entity: uid.into(), + animation_info: animation_info.clone(), + }, + ); } - - self.clients.notify_ingame_except( - entity, - ServerMsg::EntityAnimation { - entity: uid.into(), - animation_history, - }, - ); } - // Update animation last/current state. - for (entity, mut animation_history) in ( + // Sync deaths. + let todo_remove = ( &self.state.ecs().entities(), - &mut self.state.ecs().write_storage::(), + &self.state.ecs().read_storage::(), ) .join() - { - animation_history.last = Some(animation_history.current); + .map(|(entity, _)| entity) + .collect::>(); + + for entity in todo_remove { + self.state.ecs_mut().delete_entity_synced(entity); } // Remove all force flags. diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 4a75a4b3ba..46ac1c7e2f 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -74,13 +74,10 @@ impl PlayState for CharSelectionState { return PlayStateResult::Pop; } ui::Event::Play => { - self.client - .borrow_mut() - .postbox - .send_message(ClientMsg::Character { - name: self.char_selection_ui.character_name.clone(), - body: comp::Body::Humanoid(self.char_selection_ui.character_body), - }); + self.client.borrow_mut().request_character( + self.char_selection_ui.character_name.clone(), + comp::Body::Humanoid(self.char_selection_ui.character_body), + ); return PlayStateResult::Switch(Box::new(SessionState::new( &mut global_state.window, self.client.clone(), diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 48fbe30c87..676265141f 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -347,13 +347,13 @@ 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, actor, animation_history, stats) in ( + for (entity, pos, vel, dir, actor, animation_info, stats) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), - &ecs.read_storage::(), + &ecs.read_storage::(), ecs.read_storage::().maybe(), ) .join() @@ -365,21 +365,21 @@ impl FigureMgr { FigureState::new(renderer, CharacterSkeleton::new()) }); - let target_skeleton = match animation_history.current { + let target_skeleton = match animation_info.animation { comp::Animation::Idle => character::IdleAnimation::update_skeleton( state.skeleton_mut(), time, - animation_history.time, + animation_info.time, ), comp::Animation::Run => character::RunAnimation::update_skeleton( state.skeleton_mut(), (vel.0.magnitude(), time), - animation_history.time, + animation_info.time, ), comp::Animation::Jump => character::JumpAnimation::update_skeleton( state.skeleton_mut(), time, - animation_history.time, + animation_info.time, ), comp::Animation::Attack => character::AttackAnimation::update_skeleton( state.skeleton_mut(), @@ -390,7 +390,7 @@ impl FigureMgr { character::GlidingAnimation::update_skeleton( state.skeleton_mut(), time, - animation_history.time, + animation_info.time, ) } }; @@ -404,21 +404,21 @@ impl FigureMgr { FigureState::new(renderer, QuadrupedSkeleton::new()) }); - let target_skeleton = match animation_history.current { + let target_skeleton = match animation_info.animation { comp::Animation::Run => quadruped::RunAnimation::update_skeleton( state.skeleton_mut(), (vel.0.magnitude(), time), - animation_history.time, + animation_info.time, ), comp::Animation::Idle => quadruped::IdleAnimation::update_skeleton( state.skeleton_mut(), time, - animation_history.time, + animation_info.time, ), comp::Animation::Jump => quadruped::JumpAnimation::update_skeleton( state.skeleton_mut(), (vel.0.magnitude(), time), - animation_history.time, + animation_info.time, ), // TODO! diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index a74c01fd0f..d533eeb882 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -9,6 +9,7 @@ use crate::{ }; use client::{self, Client, Input, InputEvent}; use common::clock::Clock; +use glutin::MouseButton; use std::{cell::RefCell, mem, rc::Rc, time::Duration}; use vek::*; @@ -138,7 +139,11 @@ impl PlayState for SessionState { Event::Close => { return PlayStateResult::Shutdown; } - // Movement Key Pressed + // Attack key pressed + Event::Click(MouseButton::Left, state) => { + self.input_events.push(InputEvent::AttackStarted) + } + // Movement key pressed Event::KeyDown(Key::MoveForward) => self.key_state.up = true, Event::KeyDown(Key::MoveBack) => self.key_state.down = true, Event::KeyDown(Key::MoveLeft) => self.key_state.left = true, @@ -148,7 +153,7 @@ impl PlayState for SessionState { self.key_state.jump = true; } Event::KeyDown(Key::Glide) => self.key_state.glide = true, - // Movement Key Released + // Movement key released Event::KeyUp(Key::MoveForward) => self.key_state.up = false, Event::KeyUp(Key::MoveBack) => self.key_state.down = false, Event::KeyUp(Key::MoveLeft) => self.key_state.left = false, diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index fc43802698..75d33916d2 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -3,6 +3,7 @@ use crate::{ settings::Settings, ui, Error, }; +use glutin::{ElementState, MouseButton}; use std::collections::HashMap; use vek::*; @@ -124,7 +125,11 @@ impl Window { events.push(Event::Resize(Vec2::new(width as u32, height as u32))); } glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), - + glutin::WindowEvent::MouseInput { button, state, .. } + if cursor_grabbed && state == ElementState::Pressed => + { + events.push(Event::Click(button, state)) + } glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode { Some(keycode) => match key_map.get(&keycode) { @@ -292,6 +297,7 @@ pub enum Event { /// A key has been typed that corresponds to a specific character. Char(char), /// The cursor has been panned across the screen while grabbed. + Click(MouseButton, ElementState), CursorPan(Vec2), /// The camera has been requested to zoom. Zoom(f32), From 8af3ca5317d5d7e698363089b7574cd45a3e74c0 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 16:53:07 +0200 Subject: [PATCH 02/34] Fix animations Former-commit-id: 20285b42be6f1858105cc4287e357ea254a8ce35 --- common/src/sys/animation.rs | 14 ++++++-------- common/src/sys/mod.rs | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs index 0978dd0c9c..df376112fa 100644 --- a/common/src/sys/animation.rs +++ b/common/src/sys/animation.rs @@ -4,7 +4,7 @@ use vek::*; // Crate use crate::{ - comp::{phys::Pos, ActionState, ActionEvent, Control, Stats}, + comp::{phys::Pos, Animation, AnimationInfo, Control, Stats}, state::DeltaTime, }; @@ -12,14 +12,12 @@ use crate::{ pub struct Sys; impl<'a> System<'a> for Sys { - type SystemData = ( - Read<'a, DeltaTime>, - WriteStorage<'a, ActionState>, - ); + type SystemData = (Read<'a, DeltaTime>, WriteStorage<'a, AnimationInfo>); - fn run(&mut self, (dt, mut action_states): Self::SystemData) { - for (dt, mut animation) in (dt, &mut animation).join() { - animation.time += dt.0 as f64; + fn run(&mut self, (dt, mut animation_infos): Self::SystemData) { + for (mut animation_info) in (&mut animation_infos).join() { + animation_info.time += dt.0 as f64; + &animation_info.time; } } } diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index cc242e6cbf..c27ecee387 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -1,5 +1,6 @@ pub mod action; pub mod agent; +pub mod animation; pub mod control; pub mod phys; mod stats; @@ -14,6 +15,7 @@ const PHYS_SYS: &str = "phys_sys"; const ANIM_SYS: &str = "anim_sys"; const MOVEMENT_SYS: &str = "movement_sys"; const ACTION_SYS: &str = "action_sys"; +const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { @@ -23,5 +25,6 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(anim::Sys, ANIM_SYS, &[]); dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(action::Sys, ACTION_SYS, &[]); + dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]); dispatch_builder.add(stats::Sys, STATS_SYS, &[ACTION_SYS]); } From b26f00ddfb7f5805111fd9daf7074c38f46ef9b0 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 17:48:56 +0200 Subject: [PATCH 03/34] Fix pvp Former-commit-id: 98480aa29c882b0bf92364b39a8284355647956b --- server/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/lib.rs b/server/src/lib.rs index c9bb50ed3c..86cd25cb4f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -149,6 +149,7 @@ impl Server { let spawn_point = state.ecs().read_resource::().0; state.write_component(entity, comp::Actor::Character { name, body }); + state.write_component(entity, comp::Stats::default()); state.write_component(entity, comp::phys::Pos(spawn_point)); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); From 449b717777ae5df57488fb65ee31dcad8639b94a Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 19:22:35 +0200 Subject: [PATCH 04/34] Go back to char selection on death Former-commit-id: a8b5ee42f432ff2da8385225b17be654420f17d1 --- client/src/lib.rs | 18 +++++++++++++++++- server/src/lib.rs | 2 ++ voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/session.rs | 8 ++++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 48ec3880bf..448c1e308f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -35,6 +35,7 @@ pub enum Event { pub struct Client { client_state: Option, + pending_state_request: bool, thread_pool: ThreadPool, last_ping: f64, @@ -79,6 +80,7 @@ impl Client { Ok(Self { client_state, + pending_state_request: false, thread_pool: threadpool::Builder::new() .thread_name("veloren-worker".into()) .build(), @@ -105,6 +107,7 @@ impl Client { pub fn request_character(&mut self, name: String, body: comp::Body) { self.postbox .send_message(ClientMsg::Character { name, body }); + self.pending_state_request = true; } pub fn set_view_distance(&mut self, view_distance: u32) { @@ -139,6 +142,17 @@ impl Client { self.entity } + /// Get the client state + #[allow(dead_code)] + pub fn get_client_state(&self) -> Option { + self.client_state + } + + /// Get the pending state request bool + pub fn is_request_pending(&self) -> bool { + self.pending_state_request + } + /// Get the current tick number. #[allow(dead_code)] pub fn get_tick(&self) -> u64 { @@ -372,12 +386,14 @@ impl Client { } ServerMsg::StateAnswer(Ok(state)) => { self.client_state = Some(state); + self.pending_state_request = false; } ServerMsg::StateAnswer(Err((error, state))) => { self.client_state = Some(state); + self.pending_state_request = false; } ServerMsg::ForceState(state) => { - self.client_state = Some(state); + self.client_state = Some(dbg!(state)); } ServerMsg::Disconnect => { self.client_state = None; diff --git a/server/src/lib.rs b/server/src/lib.rs index 86cd25cb4f..55f284068b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -586,6 +586,8 @@ impl Server { for entity in todo_remove { self.state.ecs_mut().delete_entity_synced(entity); + self.clients + .notify(entity, ServerMsg::ForceState(ClientState::Registered)); } // Remove all force flags. diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 46ac1c7e2f..e54a7035d1 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -78,7 +78,7 @@ impl PlayState for CharSelectionState { self.char_selection_ui.character_name.clone(), comp::Body::Humanoid(self.char_selection_ui.character_body), ); - return PlayStateResult::Switch(Box::new(SessionState::new( + return PlayStateResult::Push(Box::new(SessionState::new( &mut global_state.window, self.client.clone(), global_state.settings.clone(), diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index d533eeb882..54d56a7f5b 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -8,7 +8,7 @@ use crate::{ Direction, Error, GlobalState, PlayState, PlayStateResult, }; use client::{self, Client, Input, InputEvent}; -use common::clock::Clock; +use common::{clock::Clock, msg::ClientState}; use glutin::MouseButton; use std::{cell::RefCell, mem, rc::Rc, time::Duration}; use vek::*; @@ -128,7 +128,9 @@ impl PlayState for SessionState { */ // Game loop - loop { + while self.client.borrow().is_request_pending() + || self.client.borrow().get_client_state() == Some(ClientState::Character) + { // Handle window events. for event in global_state.window.fetch_events() { // Pass all events to the ui first. @@ -237,6 +239,8 @@ impl PlayState for SessionState { // Clean things up after the tick. self.cleanup(); } + + PlayStateResult::Pop } fn name(&self) -> &'static str { From fc39356cde62905512ceffb17084daa9399ef8db Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 19:58:32 +0200 Subject: [PATCH 05/34] Use correct time Former-commit-id: df33e802ee46f9ebe190be705ff8d81f856024e0 --- common/src/comp/stats.rs | 7 ++++--- common/src/state.rs | 2 +- common/src/sys/action.rs | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index def733e988..9c47b9a439 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -1,16 +1,17 @@ use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; +use crate::state::Time; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Health { pub current: u32, pub maximum: u32, - pub last_change: Option<(i32, f64)>, + pub last_change: Option<(i32, Time)>, } impl Health { - pub fn change_by(&mut self, amount: i32, current_time: f64) { + pub fn change_by(&mut self, amount: i32, current_time: Time) { self.current = (self.current as i32 + amount).max(0) as u32; - self.last_change = Some((amount, current_time)); + self.last_change = dbg!(Some((amount, current_time))); } } diff --git a/common/src/state.rs b/common/src/state.rs index e42e78ed9a..a68687639a 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -28,7 +28,7 @@ const DAY_CYCLE_FACTOR: f64 = 24.0 * 60.0; pub struct TimeOfDay(f64); /// A resource that stores the tick (i.e: physics) time. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct Time(f64); /// A resource that stores the time since the previous tick. diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs index e82bb67d95..2178c1f8fc 100644 --- a/common/src/sys/action.rs +++ b/common/src/sys/action.rs @@ -5,7 +5,7 @@ use vek::*; // Crate use crate::{ comp::{phys::Pos, Action, Actions, Control, Stats}, - state::DeltaTime, + state::{Time, DeltaTime}, }; // Basic ECS AI agent system @@ -14,13 +14,14 @@ pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, + Read<'a, Time>, Read<'a, DeltaTime>, WriteStorage<'a, Actions>, ReadStorage<'a, Pos>, WriteStorage<'a, Stats>, ); - fn run(&mut self, (entities, dt, mut actions, positions, mut stats): Self::SystemData) { + fn run(&mut self, (entities, time, dt, mut actions, positions, mut stats): Self::SystemData) { for (a, mut actions_a, pos_a) in (&entities, &mut actions, &positions).join() { for event in actions_a.0.drain(..) { match event { @@ -30,7 +31,7 @@ impl<'a> System<'a> for Sys { continue; } if pos_a.0.distance_squared(pos_b.0) < 50.0 { - &mut stat_b.hp.change_by(-60, 0.0); // TODO: variable damage and current time + &mut stat_b.hp.change_by(-60, *time); // TODO: variable damage &stat_b.hp; } } From 7d683affe9ed176218e802991bcf368803c70286 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 20:08:29 +0200 Subject: [PATCH 06/34] Use clients.notify() Former-commit-id: 3921579a91033cbdf85929e172fc987a26fdcc9c --- server/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 55f284068b..adfac612ff 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -513,7 +513,7 @@ impl Server { .join() { // Animation - client.postbox.send_message(ServerMsg::EntityAnimation { + client.notify(ServerMsg::EntityAnimation { entity: uid.into(), animation_info: animation_info, }); From ad5dcb41588efde53c6aa1acba1bd75e7c9b8b19 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 20:22:45 +0200 Subject: [PATCH 07/34] Make use of states in char-selection Former-commit-id: f74d4811bebb0e60093a96d70feeedaae8bc6c04 --- client/src/lib.rs | 1 + common/src/comp/stats.rs | 2 +- common/src/sys/action.rs | 2 +- voxygen/src/menu/char_selection/mod.rs | 8 ++++++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 448c1e308f..511d32079e 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -102,6 +102,7 @@ impl Client { pub fn register(&mut self, player: comp::Player) { self.postbox.send_message(ClientMsg::Register { player }); + self.pending_state_request = true; } pub fn request_character(&mut self, name: String, body: comp::Body) { diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 9c47b9a439..3b165f1337 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -1,5 +1,5 @@ -use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; use crate::state::Time; +use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Health { diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs index 2178c1f8fc..4817b54206 100644 --- a/common/src/sys/action.rs +++ b/common/src/sys/action.rs @@ -5,7 +5,7 @@ use vek::*; // Crate use crate::{ comp::{phys::Pos, Action, Actions, Control, Stats}, - state::{Time, DeltaTime}, + state::{DeltaTime, Time}, }; // Basic ECS AI agent system diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index e54a7035d1..2e1f5a3635 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -8,7 +8,7 @@ use crate::{ Direction, GlobalState, PlayState, PlayStateResult, }; use client::{self, Client}; -use common::{clock::Clock, comp, msg::ClientMsg}; +use common::{clock::Clock, comp, msg::ClientMsg, msg::ClientState}; use scene::Scene; use std::{cell::RefCell, rc::Rc, time::Duration}; use ui::CharSelectionUi; @@ -46,7 +46,9 @@ impl PlayState for CharSelectionState { // Set up an fps clock. let mut clock = Clock::new(); - loop { + while self.client.borrow().is_request_pending() + || self.client.borrow().get_client_state() == Some(ClientState::Registered) + { // Handle window events. for event in global_state.window.fetch_events() { match event { @@ -122,6 +124,8 @@ impl PlayState for CharSelectionState { // Wait for the next tick. clock.tick(Duration::from_millis(1000 / FPS)); } + + PlayStateResult::Pop } fn name(&self) -> &'static str { From a0918d11b6ff2399a176b91f565232f6d3e9bbec Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 22:14:18 +0200 Subject: [PATCH 08/34] Fix red effect Former-commit-id: 1fd90a40aaaccb98aeb34715ee7cad5c0b3b3de7 --- common/src/comp/stats.rs | 6 +++--- common/src/state.rs | 2 +- common/src/sys/action.rs | 20 ++++++++++++++------ common/src/sys/animation.rs | 1 - common/src/sys/stats.rs | 10 +++++++--- voxygen/src/scene/figure.rs | 27 ++++++++++----------------- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 3b165f1337..3901867ebc 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -5,13 +5,13 @@ use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; pub struct Health { pub current: u32, pub maximum: u32, - pub last_change: Option<(i32, Time)>, + pub last_change: Option<(i32, f64)>, } impl Health { - pub fn change_by(&mut self, amount: i32, current_time: Time) { + pub fn change_by(&mut self, amount: i32) { self.current = (self.current as i32 + amount).max(0) as u32; - self.last_change = dbg!(Some((amount, current_time))); + self.last_change = Some((amount, 0.0)); } } diff --git a/common/src/state.rs b/common/src/state.rs index a68687639a..192dedf9d1 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -29,7 +29,7 @@ pub struct TimeOfDay(f64); /// A resource that stores the tick (i.e: physics) time. #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] -pub struct Time(f64); +pub struct Time(pub f64); /// A resource that stores the time since the previous tick. #[derive(Default)] diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs index 4817b54206..404ddcb8a7 100644 --- a/common/src/sys/action.rs +++ b/common/src/sys/action.rs @@ -4,7 +4,10 @@ use vek::*; // Crate use crate::{ - comp::{phys::Pos, Action, Actions, Control, Stats}, + comp::{ + phys::{Pos, Vel}, + Action, Actions, Control, Stats, + }, state::{DeltaTime, Time}, }; @@ -18,21 +21,26 @@ impl<'a> System<'a> for Sys { Read<'a, DeltaTime>, WriteStorage<'a, Actions>, ReadStorage<'a, Pos>, + WriteStorage<'a, Vel>, WriteStorage<'a, Stats>, ); - fn run(&mut self, (entities, time, dt, mut actions, positions, mut stats): Self::SystemData) { - for (a, mut actions_a, pos_a) in (&entities, &mut actions, &positions).join() { + fn run( + &mut self, + (entities, time, dt, mut actions, positions, mut velocities, mut stats): Self::SystemData, + ) { + for (a, actions_a, pos_a) in (&entities, &mut actions, &positions).join() { for event in actions_a.0.drain(..) { match event { Action::Attack => { - for (b, pos_b, stat_b) in (&entities, &positions, &mut stats).join() { + for (b, pos_b, stat_b, vel_b) in + (&entities, &positions, &mut stats, &mut velocities).join() + { if a == b { continue; } if pos_a.0.distance_squared(pos_b.0) < 50.0 { - &mut stat_b.hp.change_by(-60, *time); // TODO: variable damage - &stat_b.hp; + stat_b.hp.change_by(-60); // TODO: variable damage } } } diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs index df376112fa..bbbc33d379 100644 --- a/common/src/sys/animation.rs +++ b/common/src/sys/animation.rs @@ -17,7 +17,6 @@ impl<'a> System<'a> for Sys { fn run(&mut self, (dt, mut animation_infos): Self::SystemData) { for (mut animation_info) in (&mut animation_infos).join() { animation_info.time += dt.0 as f64; - &animation_info.time; } } } diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index e979b5e1a4..86f0b9cbb6 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -14,15 +14,19 @@ pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, - ReadStorage<'a, Stats>, + Read<'a, DeltaTime>, + WriteStorage<'a, Stats>, WriteStorage<'a, Dying>, ); - fn run(&mut self, (entities, stats, mut dyings): Self::SystemData) { - for (entity, stat) in (&entities, &stats).join() { + fn run(&mut self, (entities, dt, mut stats, mut dyings): Self::SystemData) { + for (entity, mut stat) in (&entities, &mut stats).join() { if stat.hp.current == 0 { dyings.insert(entity, Dying); } + if let Some(change) = &mut stat.hp.last_change { + change.1 += dt.0 as f64; + } } } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 676265141f..5e3bb54861 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -358,6 +358,15 @@ impl FigureMgr { ) .join() { + // Change in health as color! + let col = stats + .and_then(|stats| stats.hp.last_change) + .map(|(change_by, time)| { + Rgba::broadcast(1.0) + + Rgba::new(0.0, -1.0, -1.0, 0.0).map(|c| (c / (1.0 + 5.0 * time)) as f32) + }) + .unwrap_or(Rgba::broadcast(1.0)); + match actor { comp::Actor::Character { body, .. } => match body { Body::Humanoid(body) => { @@ -396,8 +405,7 @@ impl FigureMgr { }; state.skeleton.interpolate(&target_skeleton); - - state.update(renderer, pos.0, dir.0, Rgba::white()); + state.update(renderer, pos.0, dir.0, col); } Body::Quadruped(body) => { let state = self.quadruped_states.entry(entity).or_insert_with(|| { @@ -426,21 +434,6 @@ impl FigureMgr { }; state.skeleton.interpolate(&target_skeleton); - - // Change in health as color! - let col = stats - .and_then(|stats| stats.hp.last_change) - .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) - .unwrap_or(Rgba::broadcast(1.0)); - - // Change in health as color! - let col = stats - .and_then(|stats| stats.hp.last_change) - .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) - .unwrap_or(Rgba::broadcast(1.0)); - - state.update(renderer, pos.0, dir.0, col); - state.update(renderer, pos.0, dir.0, col); } }, From 30bf1cde10a739c535089b39f7a22caa80a2ea95 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 22:46:53 +0200 Subject: [PATCH 09/34] Add knockback Former-commit-id: a703eb937ef7094a085548ca3197a575059855a0 --- common/src/state.rs | 1 + common/src/sys/action.rs | 10 +++++++--- server/src/lib.rs | 1 - 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/src/state.rs b/common/src/state.rs index 192dedf9d1..8b9b4e7965 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -103,6 +103,7 @@ impl State { ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); + ecs.register::(); // Register unsynced (or synced by other means) components. ecs.register::(); diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs index 404ddcb8a7..b8b55a046f 100644 --- a/common/src/sys/action.rs +++ b/common/src/sys/action.rs @@ -5,7 +5,7 @@ use vek::*; // Crate use crate::{ comp::{ - phys::{Pos, Vel}, + phys::{ForceUpdate, Pos, Vel}, Action, Actions, Control, Stats, }, state::{DeltaTime, Time}, @@ -23,11 +23,12 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Stats>, + WriteStorage<'a, ForceUpdate>, ); fn run( &mut self, - (entities, time, dt, mut actions, positions, mut velocities, mut stats): Self::SystemData, + (entities, time, dt, mut actions, positions, mut velocities, mut stats, mut force_updates): Self::SystemData, ) { for (a, actions_a, pos_a) in (&entities, &mut actions, &positions).join() { for event in actions_a.0.drain(..) { @@ -40,7 +41,10 @@ impl<'a> System<'a> for Sys { continue; } if pos_a.0.distance_squared(pos_b.0) < 50.0 { - stat_b.hp.change_by(-60); // TODO: variable damage + stat_b.hp.change_by(-10); // TODO: variable damage + vel_b.0 += (pos_b.0 - pos_a.0).normalized() * 20.0; + vel_b.0.z = 20.0; + force_updates.insert(b, ForceUpdate); } } } diff --git a/server/src/lib.rs b/server/src/lib.rs index adfac612ff..9dcf47acc7 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -73,7 +73,6 @@ impl Server { let (chunk_tx, chunk_rx) = mpsc::channel(); let mut state = State::new(); - state.ecs_mut().register::(); state .ecs_mut() .add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 280.0))); From 69cd712ca96ddad6b07aeb6aeea351d876a6fbbc Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 23:43:45 +0200 Subject: [PATCH 10/34] Remove all outdated components when dieing Former-commit-id: 9f320fba441998af24bf52be92260264f183f0d8 --- server/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 9dcf47acc7..885637113d 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -575,7 +575,7 @@ impl Server { } // Sync deaths. - let todo_remove = ( + let todo_kill = ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), ) @@ -583,8 +583,15 @@ impl Server { .map(|(entity, _)| entity) .collect::>(); - for entity in todo_remove { - self.state.ecs_mut().delete_entity_synced(entity); + for entity in todo_kill { + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.ecs_mut().write_storage::().remove(entity); self.clients .notify(entity, ServerMsg::ForceState(ClientState::Registered)); } From 616b922e3673d437204ed81537451bdc1842e9db Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 19 May 2019 23:54:09 +0200 Subject: [PATCH 11/34] Add /kill command for easier testing Former-commit-id: 9f27dcfd5c99327fdc6e30cac30afa5cc75cec95 --- server/src/cmd.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server/src/cmd.rs b/server/src/cmd.rs index b31ed2ee28..48ee5f0236 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -75,6 +75,12 @@ lazy_static! { "/tp : Teleport to another player", handle_tp ), + ChatCommand::new( + "kill", + "{}", + "/kill : Kill yourself", + handle_kill + ), ChatCommand::new( "pet", "{}", @@ -132,6 +138,12 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch } } +fn handle_kill(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { + server + .state + .write_component::(entity, comp::Dying) +} + fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { let opt_alias = scan_fmt!(&args, action.arg_fmt, String); match opt_alias { From 36e890bbd88da809a79de9afe0d2bca3b3acd26f Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 20 May 2019 00:20:25 +0200 Subject: [PATCH 12/34] Fix client states server-side Former-commit-id: 701dd2a7f53bd0f1943cbeb61cc9c251228a4b5f --- server/src/client.rs | 8 ++++++++ server/src/lib.rs | 48 +++++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index d4532d2966..61cdf9815a 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -47,6 +47,14 @@ impl Clients { self.clients.insert(entity, client); } + pub fn get<'a>(&'a self, entity: &EcsEntity) -> Option<&'a Client> { + self.clients.get(entity) + } + + pub fn get_mut<'a>(&'a mut self, entity: &EcsEntity) -> Option<&'a mut Client> { + self.clients.get_mut(entity) + } + pub fn remove_if bool>(&mut self, mut f: F) { self.clients.retain(|entity, client| !f(*entity, client)); } diff --git a/server/src/lib.rs b/server/src/lib.rs index 885637113d..b498c4e78a 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -162,8 +162,7 @@ impl Server { state.write_component(entity, comp::Actions::new()); // Tell the client its request was successful. - client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); - client.client_state = ClientState::Character; + client.allow_state(ClientState::Character); } /// Execute a single server tick, handle input and update the game state by the given duration. @@ -584,16 +583,41 @@ impl Server { .collect::>(); for entity in todo_kill { - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.state.ecs_mut().write_storage::().remove(entity); - self.clients - .notify(entity, ServerMsg::ForceState(ClientState::Registered)); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + if let Some(client) = self.clients.get_mut(&entity) { + client.force_state(ClientState::Registered); + } } // Remove all force flags. From f5751d65b13fbb5d219e9ffd2c5db43c6670a273 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 20 May 2019 01:00:31 +0200 Subject: [PATCH 13/34] Fix terrain not loading Former-commit-id: f9279878ab051c6083c4a1f5125531fe79151fb8 --- common/src/state.rs | 5 +++++ common/src/volumes/vol_map_2d.rs | 4 ++++ voxygen/src/menu/char_selection/mod.rs | 1 + voxygen/src/scene/terrain.rs | 4 ++++ voxygen/src/session.rs | 1 + 5 files changed, 15 insertions(+) diff --git a/common/src/state.rs b/common/src/state.rs index 8b9b4e7965..7397cc5d44 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -184,6 +184,11 @@ impl State { self.ecs.read_resource::() } + /// Get a writable reference to this state's terrain. + pub fn terrain_mut(&self) -> FetchMut { + self.ecs.write_resource::() + } + /// Insert the provided chunk into this state's terrain. pub fn insert_chunk(&mut self, key: Vec2, chunk: TerrainChunk) { if self diff --git a/common/src/volumes/vol_map_2d.rs b/common/src/volumes/vol_map_2d.rs index 79db65cee4..5b06479b7d 100644 --- a/common/src/volumes/vol_map_2d.rs +++ b/common/src/volumes/vol_map_2d.rs @@ -145,6 +145,10 @@ impl VolMap2d { self.chunks.get(&key) } + pub fn clear(&mut self) { + self.chunks.clear(); + } + pub fn remove(&mut self, key: Vec2) -> Option> { self.chunks.remove(&key) } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 2e1f5a3635..cec06a2b4a 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -45,6 +45,7 @@ impl PlayState for CharSelectionState { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { // Set up an fps clock. let mut clock = Clock::new(); + self.client.borrow_mut().state_mut().terrain_mut().clear(); while self.client.borrow().is_request_pending() || self.client.borrow().get_client_state() == Some(ClientState::Registered) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index da8bd9ec82..8c3c7b0436 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -205,4 +205,8 @@ impl Terrain { renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals); } } + + pub fn clear(&mut self) { + self.chunks.clear(); + } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 54d56a7f5b..239775cf28 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -115,6 +115,7 @@ impl PlayState for SessionState { // Set up an fps clock. let mut clock = Clock::new(); + self.client.borrow_mut().state_mut().terrain_mut().clear(); // Load a few chunks. TODO: Remove this. /* From e34a47d0d7ebdda0544c8ccad4134928e63e077a Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 20 May 2019 21:24:47 +0200 Subject: [PATCH 14/34] Fix chunk loading delay Former-commit-id: b287ab5be22ae6e4d0b10b5010e592a7a514cacb --- client/src/lib.rs | 9 ++++++++- voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/session.rs | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 511d32079e..a98e887bc7 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -137,6 +137,13 @@ impl Client { &mut self.state } + /// Remove all cached terrain + #[allow(dead_code)] + pub fn reset_terrain(&mut self) { + self.state.terrain_mut().clear(); + self.pending_chunks.clear(); + } + /// Get the player's entity. #[allow(dead_code)] pub fn entity(&self) -> EcsEntity { @@ -394,7 +401,7 @@ impl Client { self.pending_state_request = false; } ServerMsg::ForceState(state) => { - self.client_state = Some(dbg!(state)); + self.client_state = Some(state); } ServerMsg::Disconnect => { self.client_state = None; diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index cec06a2b4a..7b0d421116 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -45,7 +45,7 @@ impl PlayState for CharSelectionState { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { // Set up an fps clock. let mut clock = Clock::new(); - self.client.borrow_mut().state_mut().terrain_mut().clear(); + self.client.borrow_mut().reset_terrain(); while self.client.borrow().is_request_pending() || self.client.borrow().get_client_state() == Some(ClientState::Registered) diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 239775cf28..ef1570b983 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -115,7 +115,7 @@ impl PlayState for SessionState { // Set up an fps clock. let mut clock = Clock::new(); - self.client.borrow_mut().state_mut().terrain_mut().clear(); + self.client.borrow_mut().reset_terrain(); // Load a few chunks. TODO: Remove this. /* From ad3b8dffa1a2816985d8cee84de0d674a730316a Mon Sep 17 00:00:00 2001 From: timokoesters Date: Mon, 20 May 2019 22:27:19 +0200 Subject: [PATCH 15/34] Limit attack direction Former-commit-id: b132f01f86814d2f8dd10d6d1454b6e2a95595f8 --- common/src/sys/action.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs index b8b55a046f..98f775d31a 100644 --- a/common/src/sys/action.rs +++ b/common/src/sys/action.rs @@ -5,7 +5,7 @@ use vek::*; // Crate use crate::{ comp::{ - phys::{ForceUpdate, Pos, Vel}, + phys::{Dir, ForceUpdate, Pos, Vel}, Action, Actions, Control, Stats, }, state::{DeltaTime, Time}, @@ -22,15 +22,28 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Actions>, ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, + ReadStorage<'a, Dir>, WriteStorage<'a, Stats>, WriteStorage<'a, ForceUpdate>, ); fn run( &mut self, - (entities, time, dt, mut actions, positions, mut velocities, mut stats, mut force_updates): Self::SystemData, + ( + entities, + time, + dt, + mut actions, + positions, + mut velocities, + directions, + mut stats, + mut force_updates, + ): Self::SystemData, ) { - for (a, actions_a, pos_a) in (&entities, &mut actions, &positions).join() { + for (a, actions_a, pos_a, dir_a) in + (&entities, &mut actions, &positions, &directions).join() + { for event in actions_a.0.drain(..) { match event { Action::Attack => { @@ -40,7 +53,10 @@ impl<'a> System<'a> for Sys { if a == b { continue; } - if pos_a.0.distance_squared(pos_b.0) < 50.0 { + if a != b + && pos_a.0.distance_squared(pos_b.0) < 50.0 + && dir_a.0.angle_between_degrees(pos_b.0 - pos_a.0) < 70.0 + { stat_b.hp.change_by(-10); // TODO: variable damage vel_b.0 += (pos_b.0 - pos_a.0).normalized() * 20.0; vel_b.0.z = 20.0; From 0344f3eba8294c695df5cd0910223f2bf9e0f52d Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 22 May 2019 22:53:24 +0200 Subject: [PATCH 16/34] Implement hit time delay Former-commit-id: 6c1990645fd07e23de5eb97b6fc22f34ce09a6b7 --- chat-cli/src/main.rs | 4 +- client/src/input.rs | 24 ------- client/src/lib.rs | 55 +++------------ common/src/comp/action.rs | 20 ------ common/src/comp/agent.rs | 21 ------ common/src/comp/inputs.rs | 32 +++++++++ common/src/comp/mod.rs | 9 +-- common/src/msg/client.rs | 2 +- common/src/msg/ecs_packet.rs | 2 + common/src/state.rs | 2 +- common/src/sys/action.rs | 71 ------------------- common/src/sys/actions.rs | 34 +++++++++ common/src/sys/agent.rs | 16 ++--- common/src/sys/animation.rs | 2 +- common/src/sys/{control.rs => inputs.rs} | 88 ++++++++++++++++++++---- common/src/sys/mod.rs | 17 ++--- common/src/sys/stats.rs | 2 +- server/src/cmd.rs | 1 - server/src/lib.rs | 24 +++---- voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/session.rs | 12 ++-- 21 files changed, 197 insertions(+), 243 deletions(-) delete mode 100644 client/src/input.rs delete mode 100644 common/src/comp/action.rs create mode 100644 common/src/comp/inputs.rs delete mode 100644 common/src/sys/action.rs create mode 100644 common/src/sys/actions.rs rename common/src/sys/{control.rs => inputs.rs} (51%) diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs index b8b0ef39f5..84c04cc27e 100644 --- a/chat-cli/src/main.rs +++ b/chat-cli/src/main.rs @@ -1,4 +1,4 @@ -use client::{Client, Event, Input}; +use client::{Client, Event}; use common::{clock::Clock, comp}; use log::info; use std::time::Duration; @@ -23,7 +23,7 @@ fn main() { client.send_chat("Hello!".to_string()); loop { - let events = match client.tick(Input::default(), clock.get_last_delta()) { + let events = match client.tick(comp::Inputs::default(), clock.get_last_delta()) { Ok(events) => events, Err(err) => { println!("Error: {:?}", err); diff --git a/client/src/input.rs b/client/src/input.rs deleted file mode 100644 index d93ca202a0..0000000000 --- a/client/src/input.rs +++ /dev/null @@ -1,24 +0,0 @@ -use vek::*; - -pub enum InputEvent { - Jump, - AttackStarted, -} - -pub struct Input { - pub move_dir: Vec2, - pub jumping: bool, - pub gliding: bool, - pub events: Vec, -} - -impl Default for Input { - fn default() -> Self { - Input { - move_dir: Vec2::zero(), - jumping: false, - gliding: false, - events: Vec::new(), - } - } -} diff --git a/client/src/lib.rs b/client/src/lib.rs index a98e887bc7..b5f6acca37 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -1,13 +1,9 @@ #![feature(label_break_value, duration_float)] pub mod error; -pub mod input; // Reexports -pub use crate::{ - error::Error, - input::{Input, InputEvent}, -}; +pub use crate::error::Error; pub use specs::join::Join; pub use specs::Entity as EcsEntity; @@ -75,8 +71,8 @@ impl Client { _ => return Err(Error::ServerWentMad), }; - // Initialize ecs components the client has control over - state.write_component(entity, comp::Actions::new()); + // Initialize ecs components the client has actions over + state.write_component(entity, comp::Inputs::default()); Ok(Self { client_state, @@ -180,7 +176,7 @@ impl Client { /// Execute a single client tick, handle input and update the game state by the given duration. #[allow(dead_code)] - pub fn tick(&mut self, input: Input, dt: Duration) -> Result, Error> { + pub fn tick(&mut self, input: comp::Inputs, dt: Duration) -> Result, Error> { // This tick function is the centre of the Veloren universe. Most client-side things are // managed from here, and as such it's important that it stays organised. Please consult // the core developers before making significant changes to this code. Here is the @@ -193,45 +189,16 @@ impl Client { // 4) Perform a single LocalState tick (i.e: update the world and entities in the world) // 5) Go through the terrain update queue and apply all changes to the terrain // 6) Sync information to the server - // 7) Finish the tick, passing control of the main thread back to the frontend + // 7) Finish the tick, passing actions of the main thread back to the frontend // 1) Handle input from frontend. - for event in input.events { - match event { - InputEvent::AttackStarted => { - self.state - .ecs_mut() - .write_storage::() - .get_mut(self.entity) - .unwrap() // We initialized it in the constructor - .0 - .push(comp::Action::Attack); - } - _ => {} - } - } + // Pass character actions from frontend input to the player's entity. + // TODO: Only do this if the entity already has a Inputs component! + self.state.write_component(self.entity, input.clone()); - // Tell the server about the actions. - if let Some(actions) = self - .state - .ecs() - .read_storage::() - .get(self.entity) - { - self.postbox - .send_message(ClientMsg::PlayerActions(actions.clone())); - } - - // Pass character control from frontend input to the player's entity. - // TODO: Only do this if the entity already has a Control component! - self.state.write_component( - self.entity, - comp::Control { - move_dir: input.move_dir, - jumping: input.jumping, - gliding: input.gliding, - }, - ); + // Tell the server about the inputs. + self.postbox + .send_message(ClientMsg::PlayerInputs(input.clone())); // 2) Build up a list of events for this frame, to be passed to the frontend. let mut frontend_events = Vec::new(); diff --git a/common/src/comp/action.rs b/common/src/comp/action.rs deleted file mode 100644 index 7dfb18f9f3..0000000000 --- a/common/src/comp/action.rs +++ /dev/null @@ -1,20 +0,0 @@ -use specs::{Component, FlaggedStorage, VecStorage}; -use vek::*; - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum Action { - Attack, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Actions(pub Vec); - -impl Actions { - pub fn new() -> Self { - Self(Vec::new()) - } -} - -impl Component for Actions { - type Storage = FlaggedStorage>; -} diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 1159316afc..37a9faf6e6 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -13,24 +13,3 @@ pub enum Agent { impl Component for Agent { type Storage = VecStorage; } - -#[derive(Copy, Clone, Debug)] -pub struct Control { - pub move_dir: Vec2, - pub jumping: bool, - pub gliding: bool, -} - -impl Default for Control { - fn default() -> Self { - Self { - move_dir: Vec2::zero(), - jumping: false, - gliding: false, - } - } -} - -impl Component for Control { - type Storage = VecStorage; -} diff --git a/common/src/comp/inputs.rs b/common/src/comp/inputs.rs new file mode 100644 index 0000000000..b1d3cacc47 --- /dev/null +++ b/common/src/comp/inputs.rs @@ -0,0 +1,32 @@ +use specs::{Component, FlaggedStorage, VecStorage}; +use vek::*; + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum InputEvent { + Jump, + Attack, +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Inputs { + // Held down + pub move_dir: Vec2, + pub jumping: bool, + pub gliding: bool, + + // Event based + pub events: Vec, +} + +impl Component for Inputs { + type Storage = VecStorage; +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Actions { + pub attack_time: Option, +} + +impl Component for Actions { + type Storage = FlaggedStorage>; +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index f1e8ec8423..9f709c3eb5 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,21 +1,22 @@ -pub mod action; pub mod actor; pub mod agent; pub mod animation; +pub mod inputs; pub mod phys; pub mod player; pub mod stats; // Reexports -pub use action::Action; -pub use action::Actions; pub use actor::Actor; pub use actor::Body; pub use actor::HumanoidBody; pub use actor::QuadrupedBody; -pub use agent::{Agent, Control}; +pub use agent::Agent; pub use animation::Animation; pub use animation::AnimationInfo; +pub use inputs::Actions; +pub use inputs::InputEvent; +pub use inputs::Inputs; pub use player::Player; pub use stats::Dying; pub use stats::Stats; diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index 91e5a09373..df36cd3f06 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -16,7 +16,7 @@ pub enum ClientMsg { Ping, Pong, Chat(String), - PlayerActions(comp::Actions), + PlayerInputs(comp::Inputs), PlayerAnimation(comp::AnimationInfo), PlayerPhysics { pos: comp::phys::Pos, diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index 32af121dc4..b83fd2da54 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -23,6 +23,7 @@ sphynx::sum_type! { Actor(comp::Actor), Player(comp::Player), Stats(comp::Stats), + Actions(comp::Actions), } } // Automatically derive From for EcsCompPhantom @@ -36,6 +37,7 @@ sphynx::sum_type! { Actor(PhantomData), Player(PhantomData), Stats(PhantomData), + Actions(PhantomData), } } impl sphynx::CompPacket for EcsCompPacket { diff --git a/common/src/state.rs b/common/src/state.rs index 7397cc5d44..d88f7f3c92 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -110,10 +110,10 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); ecs.register::(); // Register synced resources used by the ECS. diff --git a/common/src/sys/action.rs b/common/src/sys/action.rs deleted file mode 100644 index 98f775d31a..0000000000 --- a/common/src/sys/action.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Library -use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; -use vek::*; - -// Crate -use crate::{ - comp::{ - phys::{Dir, ForceUpdate, Pos, Vel}, - Action, Actions, Control, Stats, - }, - state::{DeltaTime, Time}, -}; - -// Basic ECS AI agent system -pub struct Sys; - -impl<'a> System<'a> for Sys { - type SystemData = ( - Entities<'a>, - Read<'a, Time>, - Read<'a, DeltaTime>, - WriteStorage<'a, Actions>, - ReadStorage<'a, Pos>, - WriteStorage<'a, Vel>, - ReadStorage<'a, Dir>, - WriteStorage<'a, Stats>, - WriteStorage<'a, ForceUpdate>, - ); - - fn run( - &mut self, - ( - entities, - time, - dt, - mut actions, - positions, - mut velocities, - directions, - mut stats, - mut force_updates, - ): Self::SystemData, - ) { - for (a, actions_a, pos_a, dir_a) in - (&entities, &mut actions, &positions, &directions).join() - { - for event in actions_a.0.drain(..) { - match event { - Action::Attack => { - for (b, pos_b, stat_b, vel_b) in - (&entities, &positions, &mut stats, &mut velocities).join() - { - if a == b { - continue; - } - if a != b - && pos_a.0.distance_squared(pos_b.0) < 50.0 - && dir_a.0.angle_between_degrees(pos_b.0 - pos_a.0) < 70.0 - { - stat_b.hp.change_by(-10); // TODO: variable damage - vel_b.0 += (pos_b.0 - pos_a.0).normalized() * 20.0; - vel_b.0.z = 20.0; - force_updates.insert(b, ForceUpdate); - } - } - } - } - } - } - } -} diff --git a/common/src/sys/actions.rs b/common/src/sys/actions.rs new file mode 100644 index 0000000000..14b2660514 --- /dev/null +++ b/common/src/sys/actions.rs @@ -0,0 +1,34 @@ +// Library +use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; +use vek::*; + +// Crate +use crate::{ + comp::{ + phys::{Dir, Pos, Vel}, + Actions, Animation, AnimationInfo, + }, + state::DeltaTime, + terrain::TerrainMap, + vol::{ReadVol, Vox}, +}; + +// Basic ECS AI agent system +pub struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = (Entities<'a>, Read<'a, DeltaTime>, WriteStorage<'a, Actions>); + + fn run(&mut self, (entities, dt, mut actions): Self::SystemData) { + for (entity, mut action) in (&entities, &mut actions).join() { + let should_end = action.attack_time.as_mut().map_or(false, |mut time| { + *time += dt.0; + *time > 0.5 // TODO: constant + }); + + if should_end { + action.attack_time = None; + } + } + } +} diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index 87a45cd2c8..fdc5644e41 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage}; use vek::*; // Crate -use crate::comp::{phys::Pos, Agent, Control}; +use crate::comp::{phys::Pos, Agent, Inputs}; // Basic ECS AI agent system pub struct Sys; @@ -12,11 +12,11 @@ impl<'a> System<'a> for Sys { type SystemData = ( WriteStorage<'a, Agent>, ReadStorage<'a, Pos>, - WriteStorage<'a, Control>, + WriteStorage<'a, Inputs>, ); - fn run(&mut self, (mut agents, positions, mut controls): Self::SystemData) { - for (mut agent, pos, mut control) in (&mut agents, &positions, &mut controls).join() { + fn run(&mut self, (mut agents, positions, mut inputs): Self::SystemData) { + for (mut agent, pos, mut input) in (&mut agents, &positions, &mut inputs).join() { match agent { Agent::Wanderer(bearing) => { *bearing += Vec2::new(rand::random::() - 0.5, rand::random::() - 0.5) @@ -25,7 +25,7 @@ impl<'a> System<'a> for Sys { - pos.0 * 0.0002; if bearing.magnitude_squared() != 0.0 { - control.move_dir = bearing.normalized(); + input.move_dir = bearing.normalized(); } } Agent::Pet { target, offset } => { @@ -35,11 +35,11 @@ impl<'a> System<'a> for Sys { let tgt_pos = tgt_pos.0 + *offset; // Jump with target. - control.jumping = tgt_pos.z > pos.0.z + 1.0; + input.jumping = tgt_pos.z > pos.0.z + 1.0; // Move towards the target. let dist = tgt_pos.distance(pos.0); - control.move_dir = if dist > 5.0 { + input.move_dir = if dist > 5.0 { Vec2::from(tgt_pos - pos.0).normalized() } else if dist < 1.5 && dist > 0.0 { Vec2::from(pos.0 - tgt_pos).normalized() @@ -47,7 +47,7 @@ impl<'a> System<'a> for Sys { Vec2::zero() }; } - _ => control.move_dir = Vec2::zero(), + _ => input.move_dir = Vec2::zero(), } // Change offset occasionally. diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs index bbbc33d379..711e70f4be 100644 --- a/common/src/sys/animation.rs +++ b/common/src/sys/animation.rs @@ -4,7 +4,7 @@ use vek::*; // Crate use crate::{ - comp::{phys::Pos, Animation, AnimationInfo, Control, Stats}, + comp::{phys::Pos, Animation, AnimationInfo, Stats}, state::DeltaTime, }; diff --git a/common/src/sys/control.rs b/common/src/sys/inputs.rs similarity index 51% rename from common/src/sys/control.rs rename to common/src/sys/inputs.rs index 83de8436cc..2d107cd4fb 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/inputs.rs @@ -5,10 +5,10 @@ use vek::*; // Crate use crate::{ comp::{ - phys::{Dir, Pos, Vel}, - Animation, AnimationInfo, Control, + phys::{Dir, ForceUpdate, Pos, Vel}, + Actions, Animation, AnimationInfo, InputEvent, Inputs, Stats, }, - state::DeltaTime, + state::{DeltaTime, Time}, terrain::TerrainMap, vol::{ReadVol, Vox}, }; @@ -18,23 +18,47 @@ pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( - ReadExpect<'a, TerrainMap>, - Read<'a, DeltaTime>, Entities<'a>, + Read<'a, Time>, + Read<'a, DeltaTime>, + ReadExpect<'a, TerrainMap>, + WriteStorage<'a, Inputs>, + WriteStorage<'a, Actions>, ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Dir>, WriteStorage<'a, AnimationInfo>, - ReadStorage<'a, Control>, + WriteStorage<'a, Stats>, + WriteStorage<'a, ForceUpdate>, ); fn run( &mut self, - (terrain, dt, entities, pos, mut vels, mut dirs, mut animation_infos, controls): Self::SystemData, + ( + entities, + time, + dt, + terrain, + mut inputs, + mut actions, + positions, + mut velocities, + mut directions, + mut animation_infos, + mut stats, + mut force_updates, + ): Self::SystemData, ) { - for (entity, pos, mut vel, mut dir, control) in - (&entities, &pos, &mut vels, &mut dirs, &controls).join() + for (entity, inputs, pos, mut dir, mut vel) in ( + &entities, + &mut inputs, + &positions, + &mut directions, + &mut velocities, + ) + .join() { + // Handle held-down inputs let on_ground = terrain .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) .map(|vox| !vox.is_empty()) @@ -44,9 +68,9 @@ impl<'a> System<'a> for Sys { let (gliding, friction) = if on_ground { // TODO: Don't hard-code this. // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 200.0; + vel.0 += Vec2::broadcast(dt.0) * inputs.move_dir * 200.0; - if control.jumping { + if inputs.jumping { vel.0.z += 16.0; } @@ -54,9 +78,9 @@ impl<'a> System<'a> for Sys { } else { // TODO: Don't hard-code this. // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 10.0; + vel.0 += Vec2::broadcast(dt.0) * inputs.move_dir * 10.0; - if control.gliding && vel.0.z < 0.0 { + if inputs.gliding && vel.0.z < 0.0 { // TODO: Don't hard-code this. let anti_grav = 9.81 * 3.95 + vel.0.z.powf(2.0) * 0.2; vel.0.z += @@ -83,7 +107,7 @@ impl<'a> System<'a> for Sys { } let animation = if on_ground { - if control.move_dir.magnitude() > 0.01 { + if inputs.move_dir.magnitude() > 0.01 { Animation::Run } else { Animation::Idle @@ -109,5 +133,41 @@ impl<'a> System<'a> for Sys { }, ); } + for (entity, inputs, mut action, pos, dir) in ( + &entities, + &mut inputs, + &mut actions, + &positions, + &mut directions, + ) + .join() + { + // Handle event-based inputs + for event in inputs.events.drain(..) { + match event { + InputEvent::Attack => { + // Attack delay + if action.attack_time.is_some() { + continue; + } + for (b, pos_b, mut stat_b, mut vel_b) in + (&entities, &positions, &mut stats, &mut velocities).join() + { + if entity != b + && pos.0.distance_squared(pos_b.0) < 50.0 + && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 + { + action.attack_time = Some(0.0); + stat_b.hp.change_by(-10); // TODO: variable damage + vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0; + vel_b.0.z = 20.0; + force_updates.insert(b, ForceUpdate); + } + } + } + InputEvent::Jump => {} + } + } + } } } diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index c27ecee387..b8ae8cc24f 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -1,7 +1,7 @@ -pub mod action; +pub mod actions; pub mod agent; pub mod animation; -pub mod control; +pub mod inputs; pub mod phys; mod stats; @@ -10,21 +10,18 @@ use specs::DispatcherBuilder; // System names const AGENT_SYS: &str = "agent_sys"; -const CONTROL_SYS: &str = "control_sys"; +const INPUTS_SYS: &str = "inputs_sys"; +const ACTIONS_SYS: &str = "actions_sys"; const PHYS_SYS: &str = "phys_sys"; -const ANIM_SYS: &str = "anim_sys"; -const MOVEMENT_SYS: &str = "movement_sys"; -const ACTION_SYS: &str = "action_sys"; const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(phys::Sys, PHYS_SYS, &[]); - dispatch_builder.add(control::Sys, CONTROL_SYS, &[PHYS_SYS]); - dispatch_builder.add(anim::Sys, ANIM_SYS, &[]); - dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(action::Sys, ACTION_SYS, &[]); + dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]); + dispatch_builder.add(actions::Sys, ACTIONS_SYS, &[]); dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]); - dispatch_builder.add(stats::Sys, STATS_SYS, &[ACTION_SYS]); + dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]); } diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index 86f0b9cbb6..96eacddb7a 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -4,7 +4,7 @@ use vek::*; // Crate use crate::{ - comp::{Control, Dying, Stats}, + comp::{Dying, Stats}, state::DeltaTime, }; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 48ee5f0236..d6ec525fde 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -214,7 +214,6 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha "Bungo".to_owned(), comp::Body::Quadruped(comp::QuadrupedBody::random()), ) - .with(comp::Control::default()) .with(comp::Agent::Pet { target: entity, offset: Vec2::zero(), diff --git a/server/src/lib.rs b/server/src/lib.rs index b498c4e78a..b5d80fb3e2 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -98,7 +98,7 @@ impl Server { "Tobermory".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random()), ) - .with(comp::Control::default()) + .with(comp::Actions::default()) .with(comp::Agent::Wanderer(Vec2::zero())) .build(); } @@ -133,7 +133,8 @@ impl Server { .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::Actions::new()) + .with(comp::Inputs::default()) + .with(comp::Actions::default()) .with(comp::Actor::Character { name, body }) .with(comp::Stats::default()) } @@ -149,18 +150,15 @@ impl Server { state.write_component(entity, comp::Actor::Character { name, body }); state.write_component(entity, comp::Stats::default()); + state.write_component(entity, comp::Inputs::default()); + state.write_component(entity, comp::Actions::default()); + state.write_component(entity, comp::AnimationInfo::new()); state.write_component(entity, comp::phys::Pos(spawn_point)); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); - // Make sure everything is accepted. + // Make sure physics are accepted. state.write_component(entity, comp::phys::ForceUpdate); - // Set initial animation. - state.write_component(entity, comp::AnimationInfo::new()); - - // Set initial actions (none). - state.write_component(entity, comp::Actions::new()); - // Tell the client its request was successful. client.allow_state(ClientState::Character); } @@ -391,13 +389,13 @@ impl Server { | ClientState::Spectator | ClientState::Character => new_chat_msgs.push((entity, msg)), }, - ClientMsg::PlayerActions(mut actions) => { + ClientMsg::PlayerInputs(mut inputs) => { state .ecs_mut() - .write_storage::() + .write_storage::() .get_mut(entity) .map(|s| { - s.0.append(&mut actions.0); + s.events.append(&mut inputs.events); }); } ClientMsg::PlayerAnimation(animation_info) => { @@ -613,7 +611,7 @@ impl Server { .remove(entity); self.state .ecs_mut() - .write_storage::() + .write_storage::() .remove(entity); if let Some(client) = self.clients.get_mut(&entity) { client.force_state(ClientState::Registered); diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 7b0d421116..a5d167feff 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -111,7 +111,7 @@ impl PlayState for CharSelectionState { // Tick the client (currently only to keep the connection alive). self.client .borrow_mut() - .tick(client::Input::default(), clock.get_last_delta()) + .tick(comp::Inputs::default(), clock.get_last_delta()) .expect("Failed to tick the client"); self.client.borrow_mut().cleanup(); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index ef1570b983..648b79aa22 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -7,8 +7,8 @@ use crate::{ window::{Event, Key, Window}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; -use client::{self, Client, Input, InputEvent}; -use common::{clock::Clock, msg::ClientState}; +use client::{self, Client}; +use common::{comp, clock::Clock, msg::ClientState}; use glutin::MouseButton; use std::{cell::RefCell, mem, rc::Rc, time::Duration}; use vek::*; @@ -19,7 +19,7 @@ pub struct SessionState { scene: Scene, client: Rc>, key_state: KeyState, - input_events: Vec, + input_events: Vec, hud: Hud, } @@ -65,7 +65,7 @@ impl SessionState { mem::swap(&mut self.input_events, &mut input_events); for event in self.client.borrow_mut().tick( - Input { + comp::Inputs { move_dir, jumping: self.key_state.jump, gliding: self.key_state.glide, @@ -144,7 +144,7 @@ impl PlayState for SessionState { } // Attack key pressed Event::Click(MouseButton::Left, state) => { - self.input_events.push(InputEvent::AttackStarted) + self.input_events.push(comp::InputEvent::Attack) } // Movement key pressed Event::KeyDown(Key::MoveForward) => self.key_state.up = true, @@ -152,7 +152,7 @@ impl PlayState for SessionState { Event::KeyDown(Key::MoveLeft) => self.key_state.left = true, Event::KeyDown(Key::MoveRight) => self.key_state.right = true, Event::KeyDown(Key::Jump) => { - self.input_events.push(InputEvent::Jump); + self.input_events.push(comp::InputEvent::Jump); self.key_state.jump = true; } Event::KeyDown(Key::Glide) => self.key_state.glide = true, From 1826a2b4f9dd78f2f7841c48f287927de98d7173 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 23 May 2019 17:14:39 +0200 Subject: [PATCH 17/34] Implement fast respawn Former-commit-id: 17f9aceba5c40a5d3ddc2e0fd6795479487753fd --- common/src/comp/inputs.rs | 1 + common/src/comp/mod.rs | 1 + common/src/comp/player.rs | 9 ++- common/src/msg/mod.rs | 1 + common/src/state.rs | 3 +- common/src/sys/inputs.rs | 39 +++++----- server/src/lib.rs | 137 +++++++++++++++++++----------------- voxygen/src/scene/figure.rs | 35 +++++---- voxygen/src/session.rs | 47 ++++++++----- 9 files changed, 154 insertions(+), 119 deletions(-) diff --git a/common/src/comp/inputs.rs b/common/src/comp/inputs.rs index b1d3cacc47..b8870c4e86 100644 --- a/common/src/comp/inputs.rs +++ b/common/src/comp/inputs.rs @@ -5,6 +5,7 @@ use vek::*; pub enum InputEvent { Jump, Attack, + Respawn, } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 9f709c3eb5..d9612e853f 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -18,5 +18,6 @@ pub use inputs::Actions; pub use inputs::InputEvent; pub use inputs::Inputs; pub use player::Player; +pub use player::Respawn; pub use stats::Dying; pub use stats::Stats; diff --git a/common/src/comp/player.rs b/common/src/comp/player.rs index 2c895083e0..4b52c6b529 100644 --- a/common/src/comp/player.rs +++ b/common/src/comp/player.rs @@ -1,4 +1,4 @@ -use specs::{Component, FlaggedStorage, VecStorage}; +use specs::{Component, NullStorage, FlaggedStorage, VecStorage}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Player { @@ -18,3 +18,10 @@ impl Player { impl Component for Player { type Storage = FlaggedStorage>; } + + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Respawn; +impl Component for Respawn { + type Storage = NullStorage; +} diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs index a5a94e89a3..84e653e9f6 100644 --- a/common/src/msg/mod.rs +++ b/common/src/msg/mod.rs @@ -12,5 +12,6 @@ pub enum ClientState { Connected, Registered, Spectator, + Dead, Character, } diff --git a/common/src/state.rs b/common/src/state.rs index d88f7f3c92..7e330ea419 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -103,6 +103,7 @@ impl State { ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); + ecs.register_synced::(); ecs.register::(); // Register unsynced (or synced by other means) components. @@ -111,8 +112,8 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 2d107cd4fb..55c6d4f056 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -6,7 +6,7 @@ use vek::*; use crate::{ comp::{ phys::{Dir, ForceUpdate, Pos, Vel}, - Actions, Animation, AnimationInfo, InputEvent, Inputs, Stats, + Actions, Animation, AnimationInfo, Respawn, InputEvent, Inputs, Stats, }, state::{DeltaTime, Time}, terrain::TerrainMap, @@ -29,6 +29,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Dir>, WriteStorage<'a, AnimationInfo>, WriteStorage<'a, Stats>, + WriteStorage<'a, Respawn>, WriteStorage<'a, ForceUpdate>, ); @@ -46,6 +47,7 @@ impl<'a> System<'a> for Sys { mut directions, mut animation_infos, mut stats, + mut respawns, mut force_updates, ): Self::SystemData, ) { @@ -133,12 +135,9 @@ impl<'a> System<'a> for Sys { }, ); } - for (entity, inputs, mut action, pos, dir) in ( + for (entity, inputs) in ( &entities, &mut inputs, - &mut actions, - &positions, - &mut directions, ) .join() { @@ -147,24 +146,26 @@ impl<'a> System<'a> for Sys { match event { InputEvent::Attack => { // Attack delay - if action.attack_time.is_some() { - continue; - } - for (b, pos_b, mut stat_b, mut vel_b) in - (&entities, &positions, &mut stats, &mut velocities).join() - { - if entity != b - && pos.0.distance_squared(pos_b.0) < 50.0 - && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 + if let (Some(pos), Some(dir), Some(action)) = (positions.get(entity), directions.get(entity), actions.get_mut(entity)) { + for (b, pos_b, mut stat_b, mut vel_b) in + (&entities, &positions, &mut stats, &mut velocities).join() { - action.attack_time = Some(0.0); - stat_b.hp.change_by(-10); // TODO: variable damage - vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0; - vel_b.0.z = 20.0; - force_updates.insert(b, ForceUpdate); + if entity != b + && pos.0.distance_squared(pos_b.0) < 50.0 + && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 + { + action.attack_time = Some(0.0); + stat_b.hp.change_by(-10); // TODO: variable damage + vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0; + vel_b.0.z = 20.0; + force_updates.insert(b, ForceUpdate); + } } } } + InputEvent::Respawn => { + respawns.insert(entity, Respawn); + } InputEvent::Jump => {} } } diff --git a/server/src/lib.rs b/server/src/lib.rs index b5d80fb3e2..2f61b30d25 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -200,6 +200,52 @@ impl Server { // Tick the world self.world.tick(dt); + // Sync deaths. + let todo_kill = ( + &self.state.ecs().entities(), + &self.state.ecs().read_storage::(), + ) + .join() + .map(|(entity, _)| entity) + .collect::>(); + + for entity in todo_kill { + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); + if let Some(client) = self.clients.get_mut(&entity) { + client.force_state(ClientState::Dead); + } else { + //self.state.ecs_mut().delete_entity_synced(entity); + } + } + + // Handle respawns + let todo_respawn = ( + &self.state.ecs().entities(), + &self.state.ecs().read_storage::(), + ) + .join() + .map(|(entity, _)| entity) + .collect::>(); + + for entity in todo_respawn { + if let Some(client) = self.clients.get_mut(&entity) { + client.allow_state(ClientState::Character); + self.state.ecs_mut().write_storage::().remove(entity); + self.state.write_component(entity, comp::Stats::default()); + self.state.write_component(entity, comp::Actions::default()); + self.state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); + self.state.write_component(entity, comp::phys::Vel(Vec3::zero())); + self.state.write_component(entity, comp::phys::ForceUpdate); + } + } + // 5) Fetch any generated `TerrainChunk`s and insert them into the terrain. // Also, send the chunk data to anybody that is close by. if let Ok((key, chunk)) = self.chunk_rx.try_recv() { @@ -331,9 +377,9 @@ impl Server { ClientState::Registered => { client.error_state(RequestStateError::Already) } - ClientState::Spectator | ClientState::Character => { - client.allow_state(ClientState::Registered) - } + ClientState::Spectator + | ClientState::Character + | ClientState::Dead => client.allow_state(ClientState::Registered), }, ClientState::Spectator => match requested_state { // Become Registered first. @@ -343,14 +389,15 @@ impl Server { ClientState::Spectator => { client.error_state(RequestStateError::Already) } - ClientState::Registered | ClientState::Character => { - client.allow_state(ClientState::Spectator) - } + ClientState::Registered + | ClientState::Character + | ClientState::Dead => client.allow_state(ClientState::Spectator), }, // Use ClientMsg::Character instead. ClientState::Character => { client.error_state(RequestStateError::WrongMessage) } + ClientState::Dead => client.error_state(RequestStateError::Impossible), }, ClientMsg::Register { player } => match client.client_state { ClientState::Connected => { @@ -374,7 +421,9 @@ impl Server { ClientState::Connected => { client.error_state(RequestStateError::Impossible) } - ClientState::Registered | ClientState::Spectator => { + ClientState::Registered + | ClientState::Spectator + | ClientState::Dead => { Self::create_player_character(state, entity, client, name, body) } ClientState::Character => { @@ -387,17 +436,21 @@ impl Server { } ClientState::Registered | ClientState::Spectator + | ClientState::Dead | ClientState::Character => new_chat_msgs.push((entity, msg)), }, - ClientMsg::PlayerInputs(mut inputs) => { - state - .ecs_mut() - .write_storage::() - .get_mut(entity) - .map(|s| { - s.events.append(&mut inputs.events); - }); - } + ClientMsg::PlayerInputs(mut inputs) => match client.client_state { + ClientState::Character | ClientState::Dead => { + state + .ecs_mut() + .write_storage::() + .get_mut(entity) + .map(|s| { + s.events.append(&mut inputs.events); + }); + } + _ => client.error_state(RequestStateError::Impossible), + }, ClientMsg::PlayerAnimation(animation_info) => { match client.client_state { ClientState::Character => { @@ -417,7 +470,9 @@ impl Server { _ => client.error_state(RequestStateError::Impossible), }, ClientMsg::TerrainChunkRequest { key } => match client.client_state { - ClientState::Connected | ClientState::Registered => { + ClientState::Connected + | ClientState::Registered + | ClientState::Dead => { client.error_state(RequestStateError::Impossible); } ClientState::Spectator | ClientState::Character => { @@ -571,58 +626,12 @@ impl Server { } } - // Sync deaths. - let todo_kill = ( - &self.state.ecs().entities(), - &self.state.ecs().read_storage::(), - ) - .join() - .map(|(entity, _)| entity) - .collect::>(); - - for entity in todo_kill { - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - if let Some(client) = self.clients.get_mut(&entity) { - client.force_state(ClientState::Registered); - } - } - // Remove all force flags. self.state .ecs_mut() .write_storage::() .clear(); + } pub fn generate_chunk(&mut self, key: Vec2) { diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 5e3bb54861..2b0d28273e 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -12,6 +12,7 @@ use crate::{ }; use client::Client; use common::{ + msg::ClientState, assets, comp::{ self, @@ -457,22 +458,26 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, actor) in (&ecs.entities(), &ecs.read_storage::()).join() { - match actor { - comp::Actor::Character { body, .. } => { - if let Some((locals, bone_consts)) = match body { - Body::Humanoid(_) => self - .character_states - .get(&entity) - .map(|state| (state.locals(), state.bone_consts())), - Body::Quadruped(_) => self - .quadruped_states - .get(&entity) - .map(|state| (state.locals(), state.bone_consts())), - } { - let model = self.model_cache.get_or_create_model(renderer, *body, tick); + for (entity, actor, _) in (&ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::()).join() { + // Check if player is alive + + { + match actor { + comp::Actor::Character { body, .. } => { + if let Some((locals, bone_consts)) = match body { + Body::Humanoid(_) => self + .character_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), + Body::Quadruped(_) => self + .quadruped_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), + } { + let model = self.model_cache.get_or_create_model(renderer, *body, tick); - renderer.render_figure(model, globals, locals, bone_consts); + renderer.render_figure(model, globals, locals, bone_consts); + } } } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 648b79aa22..5c352c23ef 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -8,7 +8,7 @@ use crate::{ Direction, Error, GlobalState, PlayState, PlayStateResult, }; use client::{self, Client}; -use common::{comp, clock::Clock, msg::ClientState}; +use common::{clock::Clock, comp, msg::ClientState}; use glutin::MouseButton; use std::{cell::RefCell, mem, rc::Rc, time::Duration}; use vek::*; @@ -131,44 +131,53 @@ impl PlayState for SessionState { // Game loop while self.client.borrow().is_request_pending() || self.client.borrow().get_client_state() == Some(ClientState::Character) + || self.client.borrow().get_client_state() == Some(ClientState::Dead) { + let alive = self.client.borrow().get_client_state() == Some(ClientState::Character); + // Handle window events. for event in global_state.window.fetch_events() { // Pass all events to the ui first. if self.hud.handle_event(event.clone(), global_state) { continue; } - let _handled = match event { + + match event { Event::Close => { return PlayStateResult::Shutdown; } // Attack key pressed - Event::Click(MouseButton::Left, state) => { - self.input_events.push(comp::InputEvent::Attack) + Event::Click(MouseButton::Left, state) => match alive { + true => { + self.input_events.push(comp::InputEvent::Attack); + } + false => { + self.input_events.push(comp::InputEvent::Respawn); + } + _ => unreachable!() } // Movement key pressed - Event::KeyDown(Key::MoveForward) => self.key_state.up = true, - Event::KeyDown(Key::MoveBack) => self.key_state.down = true, - Event::KeyDown(Key::MoveLeft) => self.key_state.left = true, - Event::KeyDown(Key::MoveRight) => self.key_state.right = true, - Event::KeyDown(Key::Jump) => { + Event::KeyDown(Key::MoveForward) if alive => self.key_state.up = true, + Event::KeyDown(Key::MoveBack) if alive => self.key_state.down = true, + Event::KeyDown(Key::MoveLeft) if alive => self.key_state.left = true, + Event::KeyDown(Key::MoveRight) if alive => self.key_state.right = true, + Event::KeyDown(Key::Jump) if alive => { self.input_events.push(comp::InputEvent::Jump); self.key_state.jump = true; } - Event::KeyDown(Key::Glide) => self.key_state.glide = true, + Event::KeyDown(Key::Glide) if alive => self.key_state.glide = true, // Movement key released - Event::KeyUp(Key::MoveForward) => self.key_state.up = false, - Event::KeyUp(Key::MoveBack) => self.key_state.down = false, - Event::KeyUp(Key::MoveLeft) => self.key_state.left = false, - Event::KeyUp(Key::MoveRight) => self.key_state.right = false, - Event::KeyUp(Key::Jump) => self.key_state.jump = false, - Event::KeyUp(Key::Glide) => self.key_state.glide = false, + Event::KeyUp(Key::MoveForward) if alive => self.key_state.up = false, + Event::KeyUp(Key::MoveBack) if alive => self.key_state.down = false, + Event::KeyUp(Key::MoveLeft) if alive => self.key_state.left = false, + Event::KeyUp(Key::MoveRight) if alive => self.key_state.right = false, + Event::KeyUp(Key::Jump) if alive => self.key_state.jump = false, + Event::KeyUp(Key::Glide) if alive => self.key_state.glide = false, // Pass all other events to the scene event => { self.scene.handle_input_event(event); - } - }; - // TODO: Do something if the event wasn't handled? + } // TODO: Do something if the event wasn't handled? + } } // Perform an in-game tick. From 1dbca8b99421515520bf0e12caa4f0c117a236a1 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 23 May 2019 17:54:15 +0200 Subject: [PATCH 18/34] Fix respawn position Former-commit-id: c4dabc71a1c7af538e2c30acbf463340a4618cc9 --- common/src/sys/mod.rs | 3 +-- server/src/lib.rs | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index b8ae8cc24f..da6f62958b 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -19,9 +19,8 @@ const STATS_SYS: &str = "stats_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(phys::Sys, PHYS_SYS, &[]); - dispatch_builder.add(action::Sys, ACTION_SYS, &[]); - dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]); dispatch_builder.add(actions::Sys, ACTIONS_SYS, &[]); + dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]); dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]); dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]); } diff --git a/server/src/lib.rs b/server/src/lib.rs index 2f61b30d25..eb7e89a7d7 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -240,7 +240,11 @@ impl Server { self.state.ecs_mut().write_storage::().remove(entity); self.state.write_component(entity, comp::Stats::default()); self.state.write_component(entity, comp::Actions::default()); - self.state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); + self.state + .ecs_mut() + .write_storage::() + .get_mut(entity) + .map(|pos| pos.0.z += 100.0); self.state.write_component(entity, comp::phys::Vel(Vec3::zero())); self.state.write_component(entity, comp::phys::ForceUpdate); } From 3697c47e33b857fd12215d2a8a6755bc4ddc9cca Mon Sep 17 00:00:00 2001 From: timokoesters Date: Fri, 24 May 2019 21:10:18 +0200 Subject: [PATCH 19/34] Change client_state_pending to ClientState::Pending Former-commit-id: 4b6a304a138ccfbffc3b6e28d36feaa2693d01a7 --- client/src/lib.rs | 26 ++++++++------------------ common/src/msg/mod.rs | 1 + server/src/lib.rs | 6 ++++++ voxygen/src/menu/char_selection/mod.rs | 7 ++++--- voxygen/src/session.rs | 10 +++++----- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index b5f6acca37..0215168665 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -30,8 +30,7 @@ pub enum Event { } pub struct Client { - client_state: Option, - pending_state_request: bool, + client_state: ClientState, thread_pool: ThreadPool, last_ping: f64, @@ -52,7 +51,7 @@ impl Client { /// Create a new `Client`. #[allow(dead_code)] pub fn new>(addr: A, view_distance: Option) -> Result { - let mut client_state = Some(ClientState::Connected); + let mut client_state = ClientState::Connected; let mut postbox = PostBox::to(addr)?; // Wait for initial sync @@ -76,7 +75,6 @@ impl Client { Ok(Self { client_state, - pending_state_request: false, thread_pool: threadpool::Builder::new() .thread_name("veloren-worker".into()) .build(), @@ -98,13 +96,13 @@ impl Client { pub fn register(&mut self, player: comp::Player) { self.postbox.send_message(ClientMsg::Register { player }); - self.pending_state_request = true; + self.client_state = ClientState::Pending; } pub fn request_character(&mut self, name: String, body: comp::Body) { self.postbox .send_message(ClientMsg::Character { name, body }); - self.pending_state_request = true; + self.client_state = ClientState::Pending; } pub fn set_view_distance(&mut self, view_distance: u32) { @@ -148,15 +146,10 @@ impl Client { /// Get the client state #[allow(dead_code)] - pub fn get_client_state(&self) -> Option { + pub fn get_client_state(&self) -> ClientState { self.client_state } - /// Get the pending state request bool - pub fn is_request_pending(&self) -> bool { - self.pending_state_request - } - /// Get the current tick number. #[allow(dead_code)] pub fn get_tick(&self) -> u64 { @@ -360,18 +353,15 @@ impl Client { self.pending_chunks.remove(&key); } ServerMsg::StateAnswer(Ok(state)) => { - self.client_state = Some(state); - self.pending_state_request = false; + self.client_state = state; } ServerMsg::StateAnswer(Err((error, state))) => { - self.client_state = Some(state); - self.pending_state_request = false; + self.client_state = state; } ServerMsg::ForceState(state) => { - self.client_state = Some(state); + self.client_state = state; } ServerMsg::Disconnect => { - self.client_state = None; frontend_events.push(Event::Disconnect); } } diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs index 84e653e9f6..8489bb5f0c 100644 --- a/common/src/msg/mod.rs +++ b/common/src/msg/mod.rs @@ -9,6 +9,7 @@ pub use self::server::{RequestStateError, ServerMsg}; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ClientState { + Pending, Connected, Registered, Spectator, diff --git a/server/src/lib.rs b/server/src/lib.rs index eb7e89a7d7..563c7919ab 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -384,6 +384,7 @@ impl Server { ClientState::Spectator | ClientState::Character | ClientState::Dead => client.allow_state(ClientState::Registered), + ClientState::Pending => {} }, ClientState::Spectator => match requested_state { // Become Registered first. @@ -396,12 +397,14 @@ impl Server { ClientState::Registered | ClientState::Character | ClientState::Dead => client.allow_state(ClientState::Spectator), + ClientState::Pending => {} }, // Use ClientMsg::Character instead. ClientState::Character => { client.error_state(RequestStateError::WrongMessage) } ClientState::Dead => client.error_state(RequestStateError::Impossible), + ClientState::Pending => {} }, ClientMsg::Register { player } => match client.client_state { ClientState::Connected => { @@ -433,6 +436,7 @@ impl Server { ClientState::Character => { client.error_state(RequestStateError::Already) } + ClientState::Pending => {} }, ClientMsg::Chat(msg) => match client.client_state { ClientState::Connected => { @@ -442,6 +446,7 @@ impl Server { | ClientState::Spectator | ClientState::Dead | ClientState::Character => new_chat_msgs.push((entity, msg)), + ClientState::Pending => {} }, ClientMsg::PlayerInputs(mut inputs) => match client.client_state { ClientState::Character | ClientState::Dead => { @@ -490,6 +495,7 @@ impl Server { None => requested_chunks.push(key), } } + ClientState::Pending => {} }, // Always possible. ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index a5d167feff..669d004e67 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -47,9 +47,8 @@ impl PlayState for CharSelectionState { let mut clock = Clock::new(); self.client.borrow_mut().reset_terrain(); - while self.client.borrow().is_request_pending() - || self.client.borrow().get_client_state() == Some(ClientState::Registered) - { + let mut current_client_state = self.client.borrow().get_client_state(); + while let ClientState::Pending | ClientState::Registered = current_client_state { // Handle window events. for event in global_state.window.fetch_events() { match event { @@ -124,6 +123,8 @@ impl PlayState for CharSelectionState { // Wait for the next tick. clock.tick(Duration::from_millis(1000 / FPS)); + + current_client_state = self.client.borrow().get_client_state(); } PlayStateResult::Pop diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 5c352c23ef..699c790e5a 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -129,11 +129,9 @@ impl PlayState for SessionState { */ // Game loop - while self.client.borrow().is_request_pending() - || self.client.borrow().get_client_state() == Some(ClientState::Character) - || self.client.borrow().get_client_state() == Some(ClientState::Dead) - { - let alive = self.client.borrow().get_client_state() == Some(ClientState::Character); + let mut current_client_state = self.client.borrow().get_client_state(); + while let ClientState::Pending | ClientState::Character | ClientState::Dead = current_client_state { + let alive = self.client.borrow().get_client_state() == ClientState::Character; // Handle window events. for event in global_state.window.fetch_events() { @@ -248,6 +246,8 @@ impl PlayState for SessionState { // Clean things up after the tick. self.cleanup(); + + current_client_state = self.client.borrow().get_client_state(); } PlayStateResult::Pop From 15d1a789d60d564e425fc2056a131953bc5521cb Mon Sep 17 00:00:00 2001 From: timokoesters Date: Fri, 24 May 2019 21:20:28 +0200 Subject: [PATCH 20/34] Better formatting Former-commit-id: 22b83b6dd5ad145a39b236436a019c6b172787d7 --- common/src/comp/inputs.rs | 2 +- common/src/comp/player.rs | 3 +-- common/src/sys/inputs.rs | 17 +++++++-------- server/src/lib.rs | 11 ++++++---- voxygen/src/scene/figure.rs | 42 +++++++++++++++++++------------------ voxygen/src/session.rs | 21 ++++++------------- 6 files changed, 45 insertions(+), 51 deletions(-) diff --git a/common/src/comp/inputs.rs b/common/src/comp/inputs.rs index b8870c4e86..1e83462a9b 100644 --- a/common/src/comp/inputs.rs +++ b/common/src/comp/inputs.rs @@ -5,7 +5,7 @@ use vek::*; pub enum InputEvent { Jump, Attack, - Respawn, + RequestRespawn, } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] diff --git a/common/src/comp/player.rs b/common/src/comp/player.rs index 4b52c6b529..68818560e4 100644 --- a/common/src/comp/player.rs +++ b/common/src/comp/player.rs @@ -1,4 +1,4 @@ -use specs::{Component, NullStorage, FlaggedStorage, VecStorage}; +use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Player { @@ -19,7 +19,6 @@ impl Component for Player { type Storage = FlaggedStorage>; } - #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Respawn; impl Component for Respawn { diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 55c6d4f056..0bc6d86d3e 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -6,7 +6,7 @@ use vek::*; use crate::{ comp::{ phys::{Dir, ForceUpdate, Pos, Vel}, - Actions, Animation, AnimationInfo, Respawn, InputEvent, Inputs, Stats, + Actions, Animation, AnimationInfo, InputEvent, Inputs, Respawn, Stats, }, state::{DeltaTime, Time}, terrain::TerrainMap, @@ -135,18 +135,17 @@ impl<'a> System<'a> for Sys { }, ); } - for (entity, inputs) in ( - &entities, - &mut inputs, - ) - .join() - { + for (entity, inputs) in (&entities, &mut inputs).join() { // Handle event-based inputs for event in inputs.events.drain(..) { match event { InputEvent::Attack => { // Attack delay - if let (Some(pos), Some(dir), Some(action)) = (positions.get(entity), directions.get(entity), actions.get_mut(entity)) { + if let (Some(pos), Some(dir), Some(action)) = ( + positions.get(entity), + directions.get(entity), + actions.get_mut(entity), + ) { for (b, pos_b, mut stat_b, mut vel_b) in (&entities, &positions, &mut stats, &mut velocities).join() { @@ -163,7 +162,7 @@ impl<'a> System<'a> for Sys { } } } - InputEvent::Respawn => { + InputEvent::RequestRespawn => { respawns.insert(entity, Respawn); } InputEvent::Jump => {} diff --git a/server/src/lib.rs b/server/src/lib.rs index 563c7919ab..c8aed3e6d5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -207,7 +207,7 @@ impl Server { ) .join() .map(|(entity, _)| entity) - .collect::>(); + .collect::>(); for entity in todo_kill { self.state @@ -237,7 +237,10 @@ impl Server { for entity in todo_respawn { if let Some(client) = self.clients.get_mut(&entity) { client.allow_state(ClientState::Character); - self.state.ecs_mut().write_storage::().remove(entity); + self.state + .ecs_mut() + .write_storage::() + .remove(entity); self.state.write_component(entity, comp::Stats::default()); self.state.write_component(entity, comp::Actions::default()); self.state @@ -245,7 +248,8 @@ impl Server { .write_storage::() .get_mut(entity) .map(|pos| pos.0.z += 100.0); - self.state.write_component(entity, comp::phys::Vel(Vec3::zero())); + self.state + .write_component(entity, comp::phys::Vel(Vec3::zero())); self.state.write_component(entity, comp::phys::ForceUpdate); } } @@ -641,7 +645,6 @@ impl Server { .ecs_mut() .write_storage::() .clear(); - } pub fn generate_chunk(&mut self, key: Vec2) { diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 2b0d28273e..9d2083a51d 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -12,7 +12,6 @@ use crate::{ }; use client::Client; use common::{ - msg::ClientState, assets, comp::{ self, @@ -24,6 +23,7 @@ use common::{ }, figure::Segment, msg, + msg::ClientState, }; use dot_vox::DotVoxData; use specs::{Component, Entity as EcsEntity, Join, VecStorage}; @@ -458,26 +458,28 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, actor, _) in (&ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::()).join() { - // Check if player is alive - - { - match actor { - comp::Actor::Character { body, .. } => { - if let Some((locals, bone_consts)) = match body { - Body::Humanoid(_) => self - .character_states - .get(&entity) - .map(|state| (state.locals(), state.bone_consts())), - Body::Quadruped(_) => self - .quadruped_states - .get(&entity) - .map(|state| (state.locals(), state.bone_consts())), - } { - let model = self.model_cache.get_or_create_model(renderer, *body, tick); + for (entity, actor, _) in ( + &ecs.entities(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ) + .join() + { + match actor { + comp::Actor::Character { body, .. } => { + if let Some((locals, bone_consts)) = match body { + Body::Humanoid(_) => self + .character_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), + Body::Quadruped(_) => self + .quadruped_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), + } { + let model = self.model_cache.get_or_create_model(renderer, *body, tick); - renderer.render_figure(model, globals, locals, bone_consts); - } + renderer.render_figure(model, globals, locals, bone_consts); } } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 699c790e5a..e390f04b59 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -117,20 +117,11 @@ impl PlayState for SessionState { let mut clock = Clock::new(); self.client.borrow_mut().reset_terrain(); - // Load a few chunks. TODO: Remove this. - /* - for x in -6..7 { - for y in -6..7 { - for z in -1..2 { - self.client.borrow_mut().load_chunk(Vec3::new(x, y, z)); - } - } - } - */ - // Game loop let mut current_client_state = self.client.borrow().get_client_state(); - while let ClientState::Pending | ClientState::Character | ClientState::Dead = current_client_state { + while let ClientState::Pending | ClientState::Character | ClientState::Dead = + current_client_state + { let alive = self.client.borrow().get_client_state() == ClientState::Character; // Handle window events. @@ -150,10 +141,10 @@ impl PlayState for SessionState { self.input_events.push(comp::InputEvent::Attack); } false => { - self.input_events.push(comp::InputEvent::Respawn); + self.input_events.push(comp::InputEvent::RequestRespawn); } - _ => unreachable!() - } + _ => unreachable!(), + }, // Movement key pressed Event::KeyDown(Key::MoveForward) if alive => self.key_state.up = true, Event::KeyDown(Key::MoveBack) if alive => self.key_state.down = true, From 73f29e3716a5a4e4aa6ce5a78f2d9c2ce10f5d20 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Fri, 24 May 2019 22:54:40 +0200 Subject: [PATCH 21/34] More comments Former-commit-id: 762d6437fa341a33ee80088e2c5dbbdf96387df0 --- common/src/sys/inputs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 0bc6d86d3e..41ee1885c4 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -149,11 +149,15 @@ impl<'a> System<'a> for Sys { for (b, pos_b, mut stat_b, mut vel_b) in (&entities, &positions, &mut stats, &mut velocities).join() { + // Check if it is a hit if entity != b && pos.0.distance_squared(pos_b.0) < 50.0 && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 { + // Set action action.attack_time = Some(0.0); + + // Deal damage stat_b.hp.change_by(-10); // TODO: variable damage vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0; vel_b.0.z = 20.0; From 525af4c201682c18e3b537b2226fe0f1c5abff02 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 25 May 2019 13:35:37 +0200 Subject: [PATCH 22/34] Add Constant for damage fade Former-commit-id: 4b0e2ff6249ebcf814b036ba11c57ad094811e30 --- voxygen/src/scene/figure.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 9d2083a51d..09db7596b2 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -30,6 +30,8 @@ use specs::{Component, Entity as EcsEntity, Join, VecStorage}; use std::{collections::HashMap, f32}; use vek::*; +const DAMAGE_FADE_COEFFICIENT: f64 = 5.0; + pub struct FigureModelCache { models: HashMap, u64)>, } @@ -364,7 +366,7 @@ impl FigureMgr { .and_then(|stats| stats.hp.last_change) .map(|(change_by, time)| { Rgba::broadcast(1.0) - + Rgba::new(0.0, -1.0, -1.0, 0.0).map(|c| (c / (1.0 + 5.0 * time)) as f32) + + Rgba::new(0.0, -1.0, -1.0, 0.0).map(|c| (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time)) as f32) }) .unwrap_or(Rgba::broadcast(1.0)); From f4434013db05b943265ac269ddc60ede9c5f437b Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 25 May 2019 14:23:56 +0200 Subject: [PATCH 23/34] Fix clear_terrain not changing `Changes` Former-commit-id: da7b02939d6d0bc7dbef7d923fb880081f6e08aa --- client/src/lib.rs | 4 ++-- common/src/state.rs | 12 ++++++++++++ common/src/volumes/vol_map_2d.rs | 6 +++++- voxygen/src/menu/char_selection/mod.rs | 1 - voxygen/src/scene/terrain.rs | 4 ---- voxygen/src/session.rs | 2 +- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 0215168665..7a07d6b501 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -133,8 +133,8 @@ impl Client { /// Remove all cached terrain #[allow(dead_code)] - pub fn reset_terrain(&mut self) { - self.state.terrain_mut().clear(); + pub fn clear_terrain(&mut self) { + self.state.clear_terrain(); self.pending_chunks.clear(); } diff --git a/common/src/state.rs b/common/src/state.rs index 7e330ea419..c5bf86485c 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -190,6 +190,18 @@ impl State { self.ecs.write_resource::() } + /// Removes every chunk of the terrain. + pub fn clear_terrain(&mut self) { + let keys = self.terrain_mut() + .drain() + .map(|(key, _)| key) + .collect::>(); + + for key in keys { + self.remove_chunk(key); + } + } + /// Insert the provided chunk into this state's terrain. pub fn insert_chunk(&mut self, key: Vec2, chunk: TerrainChunk) { if self diff --git a/common/src/volumes/vol_map_2d.rs b/common/src/volumes/vol_map_2d.rs index 5b06479b7d..1cc45fefc2 100644 --- a/common/src/volumes/vol_map_2d.rs +++ b/common/src/volumes/vol_map_2d.rs @@ -6,7 +6,7 @@ use crate::{ dyna::{Dyna, DynaErr}, }, }; -use std::{collections::HashMap, marker::PhantomData, sync::Arc}; +use std::{collections::{hash_map, HashMap}, marker::PhantomData, sync::Arc}; use vek::*; #[derive(Debug)] @@ -149,6 +149,10 @@ impl VolMap2d { self.chunks.clear(); } + pub fn drain(&mut self) -> hash_map::Drain, Arc> { + self.chunks.drain() + } + pub fn remove(&mut self, key: Vec2) -> Option> { self.chunks.remove(&key) } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 669d004e67..1563f2e017 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -45,7 +45,6 @@ impl PlayState for CharSelectionState { fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { // Set up an fps clock. let mut clock = Clock::new(); - self.client.borrow_mut().reset_terrain(); let mut current_client_state = self.client.borrow().get_client_state(); while let ClientState::Pending | ClientState::Registered = current_client_state { diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 8c3c7b0436..da8bd9ec82 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -205,8 +205,4 @@ impl Terrain { renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals); } } - - pub fn clear(&mut self) { - self.chunks.clear(); - } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index e390f04b59..9995625a26 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -115,7 +115,7 @@ impl PlayState for SessionState { // Set up an fps clock. let mut clock = Clock::new(); - self.client.borrow_mut().reset_terrain(); + self.client.borrow_mut().clear_terrain(); // Game loop let mut current_client_state = self.client.borrow().get_client_state(); From 075c0d9e1115bc08818fc33ab71911e789bb1a01 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 25 May 2019 14:53:44 +0200 Subject: [PATCH 24/34] Use type MouseButton instead of glutin::MouseButton Former-commit-id: 7fc8b2f3f42ed45455feaa4a36e225a981b768ac --- voxygen/src/main.rs | 1 + voxygen/src/window.rs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index f48ea71175..f81f17c803 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -1,4 +1,5 @@ #![feature(drain_filter)] +#![feature(type_alias_enum_variants)] #![recursion_limit = "2048"] #[macro_use] diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 75d33916d2..f0dd30aafb 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -3,10 +3,12 @@ use crate::{ settings::Settings, ui, Error, }; -use glutin::{ElementState, MouseButton}; use std::collections::HashMap; use vek::*; +pub type MouseButton = glutin::MouseButton; +pub type ElementState = glutin::ElementState; + pub struct Window { events_loop: glutin::EventsLoop, renderer: Renderer, @@ -126,7 +128,7 @@ impl Window { } glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), glutin::WindowEvent::MouseInput { button, state, .. } - if cursor_grabbed && state == ElementState::Pressed => + if cursor_grabbed && state == glutin::ElementState::Pressed => { events.push(Event::Click(button, state)) } From 3c0121538bbecf7087a8f2bf15fdb0cff465396a Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 25 May 2019 16:39:27 +0200 Subject: [PATCH 25/34] Make key binds work with mouse events Former-commit-id: 77421b44e92d7c60c39ebcb3f94a406ef7f027ff --- voxygen/src/hud/mod.rs | 58 ++++++------- voxygen/src/session.rs | 37 ++++----- voxygen/src/settings.rs | 89 ++++++++++---------- voxygen/src/window.rs | 177 ++++++++++++++++++++-------------------- 4 files changed, 180 insertions(+), 181 deletions(-) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index eb4bf1a951..4102a718fe 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -27,7 +27,7 @@ use crate::{ scene::camera::Camera, settings::{ControlSettings, Settings}, ui::{Ingame, Ingameable, ScaleMode, Ui}, - window::{Event as WinEvent, Key, Window}, + window::{Event as WinEvent, GameInput, Window}, GlobalState, }; use client::Client; @@ -624,20 +624,10 @@ impl Hud { } true } - WinEvent::KeyDown(Key::ToggleInterface) => { - self.show.toggle_ui(); - true - } - WinEvent::KeyDown(Key::ToggleCursor) => { - self.force_ungrab = !self.force_ungrab; - if self.force_ungrab { - global_state.window.grab_cursor(false); - } - true - } _ if !self.show.ui => false, WinEvent::Zoom(_) => !cursor_grabbed && !self.ui.no_widget_capturing_mouse(), - WinEvent::KeyDown(Key::Enter) => { + + WinEvent::InputUpdate(GameInput::Enter, true) => { self.ui.focus_widget(if self.typing() { None } else { @@ -645,7 +635,7 @@ impl Hud { }); true } - WinEvent::KeyDown(Key::Escape) => { + WinEvent::InputUpdate(GameInput::Escape, true) => { if self.typing() { self.ui.focus_widget(None); } else { @@ -654,40 +644,53 @@ impl Hud { } true } - WinEvent::KeyDown(key) if !self.typing() => match key { - Key::Map => { + + // Press key while not typing + WinEvent::InputUpdate(key, true) if !self.typing() => match key { + GameInput::ToggleInterface => { + self.show.toggle_ui(); + true + } + GameInput::ToggleCursor => { + self.force_ungrab = !self.force_ungrab; + if self.force_ungrab { + global_state.window.grab_cursor(false); + } + true + } + GameInput::Map => { self.show.toggle_map(); true } - Key::Bag => { + GameInput::Bag => { self.show.toggle_bag(); true } - Key::QuestLog => { + GameInput::QuestLog => { self.show.toggle_small(SmallWindowType::QuestLog); true } - Key::CharacterWindow => { + GameInput::CharacterWindow => { self.show.toggle_char_window(); true } - Key::Social => { + GameInput::Social => { self.show.toggle_small(SmallWindowType::Social); true } - Key::Spellbook => { + GameInput::Spellbook => { self.show.toggle_small(SmallWindowType::Spellbook); true } - Key::Settings => { + GameInput::Settings => { self.show.toggle_settings(); true } - Key::Help => { + GameInput::Help => { self.show.toggle_help(); true } - Key::ToggleDebug => { + GameInput::ToggleDebug => { self.show.debug = !self.show.debug; true } @@ -697,11 +700,10 @@ impl Hud { } _ => false, }, - WinEvent::KeyDown(key) | WinEvent::KeyUp(key) => match key { - Key::ToggleCursor => false, - _ => self.typing(), - }, + // Else the player is typing in chat + WinEvent::InputUpdate(key, _) => self.typing(), WinEvent::Char(_) => self.typing(), + _ => false, }; // Handle cursor grab. diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 9995625a26..dbaa93db75 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -4,7 +4,7 @@ use crate::{ render::Renderer, scene::Scene, settings::Settings, - window::{Event, Key, Window}, + window::{Event, GameInput, Window}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; use client::{self, Client}; @@ -136,32 +136,23 @@ impl PlayState for SessionState { return PlayStateResult::Shutdown; } // Attack key pressed - Event::Click(MouseButton::Left, state) => match alive { - true => { - self.input_events.push(comp::InputEvent::Attack); - } - false => { - self.input_events.push(comp::InputEvent::RequestRespawn); - } - _ => unreachable!(), + Event::InputUpdate(GameInput::Attack, state) => { + self.input_events.push(comp::InputEvent::Attack); + //self.input_events.push(comp::InputEvent::RequestRespawn); }, - // Movement key pressed - Event::KeyDown(Key::MoveForward) if alive => self.key_state.up = true, - Event::KeyDown(Key::MoveBack) if alive => self.key_state.down = true, - Event::KeyDown(Key::MoveLeft) if alive => self.key_state.left = true, - Event::KeyDown(Key::MoveRight) if alive => self.key_state.right = true, - Event::KeyDown(Key::Jump) if alive => { + Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state, + Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state, + Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state, + Event::InputUpdate(GameInput::MoveRight, state) => self.key_state.right = state, + Event::InputUpdate(GameInput::Glide, state) => self.key_state.glide = state, + Event::InputUpdate(GameInput::Jump, true) => { self.input_events.push(comp::InputEvent::Jump); self.key_state.jump = true; } - Event::KeyDown(Key::Glide) if alive => self.key_state.glide = true, - // Movement key released - Event::KeyUp(Key::MoveForward) if alive => self.key_state.up = false, - Event::KeyUp(Key::MoveBack) if alive => self.key_state.down = false, - Event::KeyUp(Key::MoveLeft) if alive => self.key_state.left = false, - Event::KeyUp(Key::MoveRight) if alive => self.key_state.right = false, - Event::KeyUp(Key::Jump) if alive => self.key_state.jump = false, - Event::KeyUp(Key::Glide) if alive => self.key_state.glide = false, + Event::InputUpdate(GameInput::Jump, false) => { + self.key_state.jump = false; + } + // Pass all other events to the scene event => { self.scene.handle_input_event(event); diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 3ba043737f..14d625601d 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -1,6 +1,7 @@ +use crate::window::KeyMouse; use config::{Config, ConfigError}; use directories::ProjectDirs; -use glutin::VirtualKeyCode; +use glutin::{MouseButton, VirtualKeyCode}; use serde_derive::{Deserialize, Serialize}; use std::{fs, io::prelude::*, path::PathBuf}; use toml; @@ -19,30 +20,31 @@ pub struct Settings { /// `ControlSettings` contains keybindings. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ControlSettings { - pub toggle_cursor: VirtualKeyCode, - pub escape: VirtualKeyCode, - pub enter: VirtualKeyCode, - pub move_forward: VirtualKeyCode, - pub move_left: VirtualKeyCode, - pub move_back: VirtualKeyCode, - pub move_right: VirtualKeyCode, - pub jump: VirtualKeyCode, - pub glide: VirtualKeyCode, - pub map: VirtualKeyCode, - pub bag: VirtualKeyCode, - pub quest_log: VirtualKeyCode, - pub character_window: VirtualKeyCode, - pub social: VirtualKeyCode, - pub spellbook: VirtualKeyCode, - pub settings: VirtualKeyCode, - pub help: VirtualKeyCode, - pub toggle_interface: VirtualKeyCode, - pub toggle_debug: VirtualKeyCode, - pub fullscreen: VirtualKeyCode, - pub screenshot: VirtualKeyCode, + pub toggle_cursor: KeyMouse, + pub escape: KeyMouse, + pub enter: KeyMouse, + pub move_forward: KeyMouse, + pub move_left: KeyMouse, + pub move_back: KeyMouse, + pub move_right: KeyMouse, + pub jump: KeyMouse, + pub glide: KeyMouse, + pub map: KeyMouse, + pub bag: KeyMouse, + pub quest_log: KeyMouse, + pub character_window: KeyMouse, + pub social: KeyMouse, + pub spellbook: KeyMouse, + pub settings: KeyMouse, + pub help: KeyMouse, + pub toggle_interface: KeyMouse, + pub toggle_debug: KeyMouse, + pub fullscreen: KeyMouse, + pub screenshot: KeyMouse, pub toggle_ingame_ui: VirtualKeyCode, pub pan_sensitivity: f32, pub zoom_sensitivity: f32, + pub attack: KeyMouse, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -77,30 +79,31 @@ impl Default for Settings { fn default() -> Self { Settings { controls: ControlSettings { - toggle_cursor: VirtualKeyCode::Tab, - escape: VirtualKeyCode::Escape, - enter: VirtualKeyCode::Return, - move_forward: VirtualKeyCode::W, - move_left: VirtualKeyCode::A, - move_back: VirtualKeyCode::S, - move_right: VirtualKeyCode::D, - jump: VirtualKeyCode::Space, - glide: VirtualKeyCode::LShift, - map: VirtualKeyCode::M, - bag: VirtualKeyCode::B, - quest_log: VirtualKeyCode::L, - character_window: VirtualKeyCode::C, - social: VirtualKeyCode::O, - spellbook: VirtualKeyCode::P, - settings: VirtualKeyCode::N, - help: VirtualKeyCode::F1, - toggle_interface: VirtualKeyCode::F2, - toggle_debug: VirtualKeyCode::F3, - fullscreen: VirtualKeyCode::F11, - screenshot: VirtualKeyCode::F4, + toggle_cursor: KeyMouse::Key(VirtualKeyCode::Tab), + escape: KeyMouse::Key(VirtualKeyCode::Escape), + enter: KeyMouse::Key(VirtualKeyCode::Return), + move_forward: KeyMouse::Key(VirtualKeyCode::W), + move_left: KeyMouse::Key(VirtualKeyCode::A), + move_back: KeyMouse::Key(VirtualKeyCode::S), + move_right: KeyMouse::Key(VirtualKeyCode::D), + jump: KeyMouse::Key(VirtualKeyCode::Space), + glide: KeyMouse::Key(VirtualKeyCode::LShift), + map: KeyMouse::Key(VirtualKeyCode::M), + bag: KeyMouse::Key(VirtualKeyCode::B), + quest_log: KeyMouse::Key(VirtualKeyCode::L), + character_window: KeyMouse::Key(VirtualKeyCode::C), + social: KeyMouse::Key(VirtualKeyCode::O), + spellbook: KeyMouse::Key(VirtualKeyCode::P), + settings: KeyMouse::Key(VirtualKeyCode::N), + help: KeyMouse::Key(VirtualKeyCode::F1), + toggle_interface: KeyMouse::Key(VirtualKeyCode::F2), + toggle_debug: KeyMouse::Key(VirtualKeyCode::F3), + fullscreen: KeyMouse::Key(VirtualKeyCode::F11), + screenshot: KeyMouse::Key(VirtualKeyCode::F4), toggle_ingame_ui: VirtualKeyCode::F6, pan_sensitivity: 1.0, zoom_sensitivity: 1.0, + attack: KeyMouse::Mouse(MouseButton::Left), }, networking: NetworkingSettings { username: "Username".to_string(), diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index f0dd30aafb..46ac859517 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -3,11 +3,67 @@ use crate::{ settings::Settings, ui, Error, }; +use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use vek::*; -pub type MouseButton = glutin::MouseButton; -pub type ElementState = glutin::ElementState; +/// Represents a key that the game recognises after keyboard mapping. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +pub enum GameInput { + ToggleCursor, + MoveForward, + MoveBack, + MoveLeft, + MoveRight, + Jump, + Glide, + Enter, + Escape, + Map, + Bag, + QuestLog, + CharacterWindow, + Social, + Spellbook, + Settings, + ToggleInterface, + Help, + ToggleDebug, + Fullscreen, + Screenshot, + ToggleIngameUi, + Attack, + Respawn, +} + +/// Represents an incoming event from the window. +#[derive(Clone)] +pub enum Event { + /// The window has been requested to close. + Close, + /// The window has been resized. + Resize(Vec2), + /// A key has been typed that corresponds to a specific character. + Char(char), + /// The cursor has been panned across the screen while grabbed. + CursorPan(Vec2), + /// The camera has been requested to zoom. + Zoom(f32), + /// A key that the game recognises has been pressed or released. + InputUpdate(GameInput, bool), + /// Event that the ui uses. + Ui(ui::Event), + // The view distance has been changed + ViewDistanceChanged(u32), + /// Game settings have changed. + SettingsChanged, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +pub enum KeyMouse { + Key(glutin::VirtualKeyCode), + Mouse(glutin::MouseButton), +} pub struct Window { events_loop: glutin::EventsLoop, @@ -18,7 +74,7 @@ pub struct Window { pub zoom_sensitivity: f32, fullscreen: bool, needs_refresh_resize: bool, - key_map: HashMap, + key_map: HashMap, supplement_events: Vec, focused: bool, } @@ -45,28 +101,29 @@ impl Window { .map_err(|err| Error::BackendError(Box::new(err)))?; let mut key_map = HashMap::new(); - key_map.insert(settings.controls.toggle_cursor, Key::ToggleCursor); - key_map.insert(settings.controls.escape, Key::Escape); - key_map.insert(settings.controls.enter, Key::Enter); - key_map.insert(settings.controls.move_forward, Key::MoveForward); - key_map.insert(settings.controls.move_left, Key::MoveLeft); - key_map.insert(settings.controls.move_back, Key::MoveBack); - key_map.insert(settings.controls.move_right, Key::MoveRight); - key_map.insert(settings.controls.jump, Key::Jump); - key_map.insert(settings.controls.glide, Key::Glide); - key_map.insert(settings.controls.map, Key::Map); - key_map.insert(settings.controls.bag, Key::Bag); - key_map.insert(settings.controls.quest_log, Key::QuestLog); - key_map.insert(settings.controls.character_window, Key::CharacterWindow); - key_map.insert(settings.controls.social, Key::Social); - key_map.insert(settings.controls.spellbook, Key::Spellbook); - key_map.insert(settings.controls.settings, Key::Settings); - key_map.insert(settings.controls.help, Key::Help); - key_map.insert(settings.controls.toggle_interface, Key::ToggleInterface); - key_map.insert(settings.controls.toggle_debug, Key::ToggleDebug); - key_map.insert(settings.controls.fullscreen, Key::Fullscreen); - key_map.insert(settings.controls.screenshot, Key::Screenshot); - key_map.insert(settings.controls.toggle_ingame_ui, Key::ToggleIngameUi); + key_map.insert(settings.controls.toggle_cursor, GameInput::ToggleCursor); + key_map.insert(settings.controls.escape, GameInput::Escape); + key_map.insert(settings.controls.enter, GameInput::Enter); + key_map.insert(settings.controls.move_forward, GameInput::MoveForward); + key_map.insert(settings.controls.move_left, GameInput::MoveLeft); + key_map.insert(settings.controls.move_back, GameInput::MoveBack); + key_map.insert(settings.controls.move_right, GameInput::MoveRight); + key_map.insert(settings.controls.jump, GameInput::Jump); + key_map.insert(settings.controls.glide, GameInput::Glide); + key_map.insert(settings.controls.map, GameInput::Map); + key_map.insert(settings.controls.bag, GameInput::Bag); + key_map.insert(settings.controls.quest_log, GameInput::QuestLog); + key_map.insert(settings.controls.character_window, GameInput::CharacterWindow); + key_map.insert(settings.controls.social, GameInput::Social); + key_map.insert(settings.controls.spellbook, GameInput::Spellbook); + key_map.insert(settings.controls.settings, GameInput::Settings); + key_map.insert(settings.controls.help, GameInput::Help); + key_map.insert(settings.controls.toggle_interface, GameInput::ToggleInterface); + key_map.insert(settings.controls.toggle_debug, GameInput::ToggleDebug); + key_map.insert(settings.controls.fullscreen, GameInput::Fullscreen); + key_map.insert(settings.controls.screenshot, GameInput::Screenshot); + key_map.insert(settings.controls.toggle_ingame_ui, GameInput::ToggleIngameUi); + key_map.insert(settings.controls.attack, GameInput::Attack); Ok(Self { events_loop, @@ -128,27 +185,26 @@ impl Window { } glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), glutin::WindowEvent::MouseInput { button, state, .. } - if cursor_grabbed && state == glutin::ElementState::Pressed => + if cursor_grabbed => { - events.push(Event::Click(button, state)) + if let Some(&game_input) = key_map.get(&KeyMouse::Mouse(button)) { + events.push(Event::InputUpdate(game_input, state == glutin::ElementState::Pressed)) + } } glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode { - Some(keycode) => match key_map.get(&keycode) { - Some(Key::Fullscreen) => match input.state { + Some(key) => match key_map.get(&KeyMouse::Key(key)) { + Some(GameInput::Fullscreen) => match input.state { glutin::ElementState::Pressed => { toggle_fullscreen = !toggle_fullscreen } _ => (), }, - Some(Key::Screenshot) => match input.state { + Some(GameInput::Screenshot) => match input.state { glutin::ElementState::Pressed => take_screenshot = true, _ => {} }, - Some(&key) => events.push(match input.state { - glutin::ElementState::Pressed => Event::KeyDown(key), - glutin::ElementState::Released => Event::KeyUp(key), - }), + Some(&game_input) => events.push(Event::InputUpdate(game_input, input.state == glutin::ElementState::Pressed)), _ => {} }, _ => {} @@ -261,56 +317,3 @@ impl Window { } } } - -/// Represents a key that the game recognises after keyboard mapping. -#[derive(Clone, Copy)] -pub enum Key { - ToggleCursor, - MoveForward, - MoveBack, - MoveLeft, - MoveRight, - Jump, - Glide, - Enter, - Escape, - Map, - Bag, - QuestLog, - CharacterWindow, - Social, - Spellbook, - Settings, - ToggleInterface, - Help, - ToggleDebug, - Fullscreen, - Screenshot, - ToggleIngameUi, -} - -/// Represents an incoming event from the window. -#[derive(Clone)] -pub enum Event { - /// The window has been requested to close. - Close, - /// The window has been resized. - Resize(Vec2), - /// A key has been typed that corresponds to a specific character. - Char(char), - /// The cursor has been panned across the screen while grabbed. - Click(MouseButton, ElementState), - CursorPan(Vec2), - /// The camera has been requested to zoom. - Zoom(f32), - /// A key that the game recognises has been pressed down. - KeyDown(Key), - /// A key that the game recognises has been released down. - KeyUp(Key), - /// Event that the ui uses. - Ui(ui::Event), - // The view distance has been changed - ViewDistanceChanged(u32), - /// Game settings have changed. - SettingsChanged, -} From 4696cd2c8bc7baaf9012df4e69af19e8c79ae91f Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 25 May 2019 23:13:38 +0200 Subject: [PATCH 26/34] Add better inputs, input validation and more Former-commit-id: 3227221b12a674f66b011ce0ba734e226f223f34 --- client/src/lib.rs | 160 +++++++++++++++++-------- common/src/comp/inputs.rs | 54 ++++++--- common/src/comp/mod.rs | 9 +- common/src/comp/stats.rs | 6 + common/src/msg/client.rs | 3 +- common/src/msg/ecs_packet.rs | 4 +- common/src/state.rs | 12 +- common/src/sys/actions.rs | 31 +++-- common/src/sys/agent.rs | 28 +++-- common/src/sys/inputs.rs | 87 ++++++-------- common/src/volumes/vol_map_2d.rs | 6 +- server/src/cmd.rs | 10 +- server/src/lib.rs | 66 +++++----- voxygen/src/key_state.rs | 4 - voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/scene/figure.rs | 11 +- voxygen/src/session.rs | 40 +++---- voxygen/src/window.rs | 24 ++-- 18 files changed, 330 insertions(+), 227 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 7a07d6b501..02d024d0b4 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -70,9 +70,6 @@ impl Client { _ => return Err(Error::ServerWentMad), }; - // Initialize ecs components the client has actions over - state.write_component(entity, comp::Inputs::default()); - Ok(Self { client_state, thread_pool: threadpool::Builder::new() @@ -94,11 +91,13 @@ impl Client { }) } + /// Request a state transition to `ClientState::Registered`. pub fn register(&mut self, player: comp::Player) { self.postbox.send_message(ClientMsg::Register { player }); self.client_state = ClientState::Pending; } + /// Request a state transition to `ClientState::Character`. pub fn request_character(&mut self, name: String, body: comp::Body) { self.postbox .send_message(ClientMsg::Character { name, body }); @@ -111,24 +110,56 @@ impl Client { .send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); // Can't fail } - /// Get a reference to the client's worker thread pool. This pool should be used for any - /// computationally expensive operations that run outside of the main thread (i.e., threads that - /// block on I/O operations are exempt). + /// Send a chat message to the server. #[allow(dead_code)] - pub fn thread_pool(&self) -> &threadpool::ThreadPool { - &self.thread_pool + pub fn send_chat(&mut self, msg: String) { + self.postbox.send_message(ClientMsg::Chat(msg)) } - /// Get a reference to the client's game state. + /// Jump locally, the new positions will be synced to the server #[allow(dead_code)] - pub fn state(&self) -> &State { - &self.state + pub fn jump(&mut self) { + if self.client_state != ClientState::Character { + return; + } + self.state.write_component(self.entity, comp::Jumping); } - /// Get a mutable reference to the client's game state. + /// Start to glide locally, animation will be synced #[allow(dead_code)] - pub fn state_mut(&mut self) -> &mut State { - &mut self.state + pub fn glide(&mut self, state: bool) { + if self.client_state != ClientState::Character { + return; + } + if state { + self.state.write_component(self.entity, comp::Gliding); + } else { + self.state + .ecs_mut() + .write_storage::() + .remove(self.entity); + } + } + + /// Start to attack + #[allow(dead_code)] + pub fn attack(&mut self) { + if self.client_state != ClientState::Character { + return; + } + // TODO: Test if attack is possible using timeout + self.state + .write_component(self.entity, comp::Attacking::start()); + self.postbox.send_message(ClientMsg::Attack); + } + + /// Tell the server the client wants to respawn. + #[allow(dead_code)] + pub fn respawn(&mut self) { + if self.client_state != ClientState::Dead { + return; + } + self.postbox.send_message(ClientMsg::Respawn) } /// Remove all cached terrain @@ -138,38 +169,9 @@ impl Client { self.pending_chunks.clear(); } - /// Get the player's entity. - #[allow(dead_code)] - pub fn entity(&self) -> EcsEntity { - self.entity - } - - /// Get the client state - #[allow(dead_code)] - pub fn get_client_state(&self) -> ClientState { - self.client_state - } - - /// Get the current tick number. - #[allow(dead_code)] - pub fn get_tick(&self) -> u64 { - self.tick - } - - /// Send a chat message to the server. - #[allow(dead_code)] - pub fn send_chat(&mut self, msg: String) { - self.postbox.send_message(ClientMsg::Chat(msg)) - } - - #[allow(dead_code)] - pub fn get_ping_ms(&self) -> f64 { - self.last_ping_delta * 1000.0 - } - /// Execute a single client tick, handle input and update the game state by the given duration. #[allow(dead_code)] - pub fn tick(&mut self, input: comp::Inputs, dt: Duration) -> Result, Error> { + pub fn tick(&mut self, control: comp::Control, dt: Duration) -> Result, Error> { // This tick function is the centre of the Veloren universe. Most client-side things are // managed from here, and as such it's important that it stays organised. Please consult // the core developers before making significant changes to this code. Here is the @@ -187,11 +189,9 @@ impl Client { // 1) Handle input from frontend. // Pass character actions from frontend input to the player's entity. // TODO: Only do this if the entity already has a Inputs component! - self.state.write_component(self.entity, input.clone()); - - // Tell the server about the inputs. - self.postbox - .send_message(ClientMsg::PlayerInputs(input.clone())); + if self.client_state == ClientState::Character { + self.state.write_component(self.entity, control.clone()); + } // 2) Build up a list of events for this frame, to be passed to the frontend. let mut frontend_events = Vec::new(); @@ -288,6 +288,25 @@ impl Client { } // 7) Finish the tick, pass control back to the frontend. + + // Cleanup + self.state + .ecs_mut() + .write_storage::() + .remove(self.entity); + self.state + .ecs_mut() + .write_storage::() + .remove(self.entity); + self.state + .ecs_mut() + .write_storage::() + .remove(self.entity); + self.state + .ecs_mut() + .write_storage::() + .remove(self.entity); + self.tick += 1; Ok(frontend_events) } @@ -378,6 +397,49 @@ impl Client { Ok(frontend_events) } + + /// Get the player's entity. + #[allow(dead_code)] + pub fn entity(&self) -> EcsEntity { + self.entity + } + + /// Get the client state + #[allow(dead_code)] + pub fn get_client_state(&self) -> ClientState { + self.client_state + } + + /// Get the current tick number. + #[allow(dead_code)] + pub fn get_tick(&self) -> u64 { + self.tick + } + + #[allow(dead_code)] + pub fn get_ping_ms(&self) -> f64 { + self.last_ping_delta * 1000.0 + } + + /// Get a reference to the client's worker thread pool. This pool should be used for any + /// computationally expensive operations that run outside of the main thread (i.e., threads that + /// block on I/O operations are exempt). + #[allow(dead_code)] + pub fn thread_pool(&self) -> &threadpool::ThreadPool { + &self.thread_pool + } + + /// Get a reference to the client's game state. + #[allow(dead_code)] + pub fn state(&self) -> &State { + &self.state + } + + /// Get a mutable reference to the client's game state. + #[allow(dead_code)] + pub fn state_mut(&mut self) -> &mut State { + &mut self.state + } } impl Drop for Client { diff --git a/common/src/comp/inputs.rs b/common/src/comp/inputs.rs index 1e83462a9b..ce55110ce0 100644 --- a/common/src/comp/inputs.rs +++ b/common/src/comp/inputs.rs @@ -1,33 +1,49 @@ -use specs::{Component, FlaggedStorage, VecStorage}; +use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; use vek::*; -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum InputEvent { - Jump, - Attack, - RequestRespawn, +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Control { + pub move_dir: Vec2, } +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Respawning; + #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] -pub struct Inputs { - // Held down - pub move_dir: Vec2, - pub jumping: bool, - pub gliding: bool, - - // Event based - pub events: Vec, +pub struct Attacking { + pub time: f32, + pub applied: bool, } +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Jumping; -impl Component for Inputs { +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Gliding; + +impl Component for Control { type Storage = VecStorage; } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] -pub struct Actions { - pub attack_time: Option, +impl Component for Respawning { + type Storage = NullStorage; } -impl Component for Actions { +impl Attacking { + pub fn start() -> Self { + Self { + time: 0.0, + applied: false, + } + } +} +impl Component for Attacking { type Storage = FlaggedStorage>; } + +impl Component for Jumping { + type Storage = NullStorage; +} + +impl Component for Gliding { + type Storage = NullStorage; +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index d9612e853f..03fb57f617 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -14,10 +14,11 @@ pub use actor::QuadrupedBody; pub use agent::Agent; pub use animation::Animation; pub use animation::AnimationInfo; -pub use inputs::Actions; -pub use inputs::InputEvent; -pub use inputs::Inputs; +pub use inputs::Attacking; +pub use inputs::Control; +pub use inputs::Gliding; +pub use inputs::Jumping; +pub use inputs::Respawning; pub use player::Player; -pub use player::Respawn; pub use stats::Dying; pub use stats::Stats; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 3901867ebc..a3c6ee49d1 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -21,6 +21,12 @@ pub struct Stats { pub xp: u32, } +impl Stats { + pub fn is_dead(&self) -> bool { + self.hp.current == 0 + } +} + impl Default for Stats { fn default() -> Self { Self { diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index df36cd3f06..b340b1797b 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -11,12 +11,13 @@ pub enum ClientMsg { name: String, body: comp::Body, }, + Attack, + Respawn, RequestState(ClientState), SetViewDistance(u32), Ping, Pong, Chat(String), - PlayerInputs(comp::Inputs), PlayerAnimation(comp::AnimationInfo), PlayerPhysics { pos: comp::phys::Pos, diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index b83fd2da54..c4e3163d62 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -23,7 +23,7 @@ sphynx::sum_type! { Actor(comp::Actor), Player(comp::Player), Stats(comp::Stats), - Actions(comp::Actions), + Attacking(comp::Attacking), } } // Automatically derive From for EcsCompPhantom @@ -37,7 +37,7 @@ sphynx::sum_type! { Actor(PhantomData), Player(PhantomData), Stats(PhantomData), - Actions(PhantomData), + Attacking(PhantomData), } } impl sphynx::CompPacket for EcsCompPacket { diff --git a/common/src/state.rs b/common/src/state.rs index c5bf86485c..61278edca3 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -103,7 +103,7 @@ impl State { ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); - ecs.register_synced::(); + ecs.register_synced::(); ecs.register::(); // Register unsynced (or synced by other means) components. @@ -111,9 +111,12 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); ecs.register::(); - ecs.register::(); ecs.register::(); ecs.register::(); @@ -192,7 +195,8 @@ impl State { /// Removes every chunk of the terrain. pub fn clear_terrain(&mut self) { - let keys = self.terrain_mut() + let keys = self + .terrain_mut() .drain() .map(|(key, _)| key) .collect::>(); diff --git a/common/src/sys/actions.rs b/common/src/sys/actions.rs index 14b2660514..05613761f4 100644 --- a/common/src/sys/actions.rs +++ b/common/src/sys/actions.rs @@ -6,7 +6,7 @@ use vek::*; use crate::{ comp::{ phys::{Dir, Pos, Vel}, - Actions, Animation, AnimationInfo, + Animation, AnimationInfo, Attacking, }, state::DeltaTime, terrain::TerrainMap, @@ -17,18 +17,27 @@ use crate::{ pub struct Sys; impl<'a> System<'a> for Sys { - type SystemData = (Entities<'a>, Read<'a, DeltaTime>, WriteStorage<'a, Actions>); + type SystemData = ( + Entities<'a>, + Read<'a, DeltaTime>, + WriteStorage<'a, Attacking>, + ); - fn run(&mut self, (entities, dt, mut actions): Self::SystemData) { - for (entity, mut action) in (&entities, &mut actions).join() { - let should_end = action.attack_time.as_mut().map_or(false, |mut time| { - *time += dt.0; - *time > 0.5 // TODO: constant - }); + fn run(&mut self, (entities, dt, mut attackings): Self::SystemData) { + for (entity, attacking) in (&entities, &mut attackings).join() { + attacking.time += dt.0; + } - if should_end { - action.attack_time = None; - } + let finished_attack = (&entities, &mut attackings) + .join() + .filter(|(e, a)| { + a.time > 0.5 // TODO: constant + }) + .map(|(e, a)| e) + .collect::>(); + + for entity in finished_attack { + attackings.remove(entity); } } } diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index fdc5644e41..ea6bc8c320 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -1,22 +1,29 @@ // Library -use specs::{Join, Read, ReadStorage, System, WriteStorage}; +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use vek::*; // Crate -use crate::comp::{phys::Pos, Agent, Inputs}; +use crate::comp::{phys::Pos, Agent, Control, Jumping}; // Basic ECS AI agent system pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( + Entities<'a>, WriteStorage<'a, Agent>, ReadStorage<'a, Pos>, - WriteStorage<'a, Inputs>, + WriteStorage<'a, Control>, + WriteStorage<'a, Jumping>, ); - fn run(&mut self, (mut agents, positions, mut inputs): Self::SystemData) { - for (mut agent, pos, mut input) in (&mut agents, &positions, &mut inputs).join() { + fn run( + &mut self, + (entities, mut agents, positions, mut controls, mut jumpings): Self::SystemData, + ) { + for (entity, agent, pos, control) in + (&entities, &mut agents, &positions, &mut controls).join() + { match agent { Agent::Wanderer(bearing) => { *bearing += Vec2::new(rand::random::() - 0.5, rand::random::() - 0.5) @@ -25,7 +32,7 @@ impl<'a> System<'a> for Sys { - pos.0 * 0.0002; if bearing.magnitude_squared() != 0.0 { - input.move_dir = bearing.normalized(); + control.move_dir = bearing.normalized(); } } Agent::Pet { target, offset } => { @@ -34,12 +41,13 @@ impl<'a> System<'a> for Sys { Some(tgt_pos) => { let tgt_pos = tgt_pos.0 + *offset; - // Jump with target. - input.jumping = tgt_pos.z > pos.0.z + 1.0; + if tgt_pos.z > pos.0.z + 1.0 { + jumpings.insert(entity, Jumping); + } // Move towards the target. let dist = tgt_pos.distance(pos.0); - input.move_dir = if dist > 5.0 { + control.move_dir = if dist > 5.0 { Vec2::from(tgt_pos - pos.0).normalized() } else if dist < 1.5 && dist > 0.0 { Vec2::from(pos.0 - tgt_pos).normalized() @@ -47,7 +55,7 @@ impl<'a> System<'a> for Sys { Vec2::zero() }; } - _ => input.move_dir = Vec2::zero(), + _ => control.move_dir = Vec2::zero(), } // Change offset occasionally. diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 41ee1885c4..6f0a4f267b 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -6,7 +6,7 @@ use vek::*; use crate::{ comp::{ phys::{Dir, ForceUpdate, Pos, Vel}, - Actions, Animation, AnimationInfo, InputEvent, Inputs, Respawn, Stats, + Animation, AnimationInfo, Attacking, Control, Gliding, Jumping, Respawning, Stats, }, state::{DeltaTime, Time}, terrain::TerrainMap, @@ -22,14 +22,16 @@ impl<'a> System<'a> for Sys { Read<'a, Time>, Read<'a, DeltaTime>, ReadExpect<'a, TerrainMap>, - WriteStorage<'a, Inputs>, - WriteStorage<'a, Actions>, ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Dir>, WriteStorage<'a, AnimationInfo>, WriteStorage<'a, Stats>, - WriteStorage<'a, Respawn>, + ReadStorage<'a, Control>, + ReadStorage<'a, Jumping>, + WriteStorage<'a, Respawning>, + WriteStorage<'a, Gliding>, + WriteStorage<'a, Attacking>, WriteStorage<'a, ForceUpdate>, ); @@ -40,27 +42,29 @@ impl<'a> System<'a> for Sys { time, dt, terrain, - mut inputs, - mut actions, positions, mut velocities, mut directions, mut animation_infos, mut stats, - mut respawns, + mut controls, + mut jumpings, + mut respawnings, + mut glidings, + mut attackings, mut force_updates, ): Self::SystemData, ) { - for (entity, inputs, pos, mut dir, mut vel) in ( + for (entity, pos, control, mut dir, mut vel) in ( &entities, - &mut inputs, &positions, + &controls, &mut directions, &mut velocities, ) .join() { - // Handle held-down inputs + // Handle held-down control let on_ground = terrain .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) .map(|vox| !vox.is_empty()) @@ -70,9 +74,9 @@ impl<'a> System<'a> for Sys { let (gliding, friction) = if on_ground { // TODO: Don't hard-code this. // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * inputs.move_dir * 200.0; + vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 200.0; - if inputs.jumping { + if jumpings.get(entity).is_some() { vel.0.z += 16.0; } @@ -80,9 +84,9 @@ impl<'a> System<'a> for Sys { } else { // TODO: Don't hard-code this. // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * inputs.move_dir * 10.0; + vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 10.0; - if inputs.gliding && vel.0.z < 0.0 { + if glidings.get(entity).is_some() && vel.0.z < 0.0 { // TODO: Don't hard-code this. let anti_grav = 9.81 * 3.95 + vel.0.z.powf(2.0) * 0.2; vel.0.z += @@ -109,12 +113,12 @@ impl<'a> System<'a> for Sys { } let animation = if on_ground { - if inputs.move_dir.magnitude() > 0.01 { + if control.move_dir.magnitude() > 0.01 { Animation::Run } else { Animation::Idle } - } else if gliding { + } else if glidings.get(entity).is_some() { Animation::Gliding } else { Animation::Jump @@ -135,42 +139,27 @@ impl<'a> System<'a> for Sys { }, ); } - for (entity, inputs) in (&entities, &mut inputs).join() { - // Handle event-based inputs - for event in inputs.events.drain(..) { - match event { - InputEvent::Attack => { - // Attack delay - if let (Some(pos), Some(dir), Some(action)) = ( - positions.get(entity), - directions.get(entity), - actions.get_mut(entity), - ) { - for (b, pos_b, mut stat_b, mut vel_b) in - (&entities, &positions, &mut stats, &mut velocities).join() - { - // Check if it is a hit - if entity != b - && pos.0.distance_squared(pos_b.0) < 50.0 - && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 - { - // Set action - action.attack_time = Some(0.0); - // Deal damage - stat_b.hp.change_by(-10); // TODO: variable damage - vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0; - vel_b.0.z = 20.0; - force_updates.insert(b, ForceUpdate); - } - } - } + for (entity, pos, dir, attacking) in + (&entities, &positions, &directions, &mut attackings).join() + { + if !attacking.applied { + for (b, pos_b, mut stat_b, mut vel_b) in + (&entities, &positions, &mut stats, &mut velocities).join() + { + // Check if it is a hit + if entity != b + && pos.0.distance_squared(pos_b.0) < 50.0 + && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 + { + // Deal damage + stat_b.hp.change_by(-10); // TODO: variable damage + vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0; + vel_b.0.z = 15.0; + force_updates.insert(b, ForceUpdate); } - InputEvent::RequestRespawn => { - respawns.insert(entity, Respawn); - } - InputEvent::Jump => {} } + attacking.applied = true; } } } diff --git a/common/src/volumes/vol_map_2d.rs b/common/src/volumes/vol_map_2d.rs index 1cc45fefc2..b552778a04 100644 --- a/common/src/volumes/vol_map_2d.rs +++ b/common/src/volumes/vol_map_2d.rs @@ -6,7 +6,11 @@ use crate::{ dyna::{Dyna, DynaErr}, }, }; -use std::{collections::{hash_map, HashMap}, marker::PhantomData, sync::Arc}; +use std::{ + collections::{hash_map, HashMap}, + marker::PhantomData, + sync::Arc, +}; use vek::*; #[derive(Debug)] diff --git a/server/src/cmd.rs b/server/src/cmd.rs index d6ec525fde..93533b3b23 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -141,7 +141,10 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch fn handle_kill(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { server .state - .write_component::(entity, comp::Dying) + .ecs_mut() + .write_storage::() + .get_mut(entity) + .map(|s| s.hp.current = 0); } fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { @@ -208,9 +211,11 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .state .read_component_cloned::(entity) { - Some(pos) => { + Some(mut pos) => { + pos.0.x += 1.0; server .create_npc( + pos, "Bungo".to_owned(), comp::Body::Quadruped(comp::QuadrupedBody::random()), ) @@ -218,7 +223,6 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha target: entity, offset: Vec2::zero(), }) - .with(pos) .build(); server .clients diff --git a/server/src/lib.rs b/server/src/lib.rs index c8aed3e6d5..99f3d118b8 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -126,15 +126,19 @@ impl Server { /// Build a non-player character. #[allow(dead_code)] - pub fn create_npc(&mut self, name: String, body: comp::Body) -> EcsEntityBuilder { + pub fn create_npc( + &mut self, + pos: comp::phys::Pos, + 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(pos) + .with(comp::Control::default()) .with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Dir(Vec3::unit_y())) - .with(comp::Inputs::default()) - .with(comp::Actions::default()) .with(comp::Actor::Character { name, body }) .with(comp::Stats::default()) } @@ -150,8 +154,7 @@ impl Server { state.write_component(entity, comp::Actor::Character { name, body }); state.write_component(entity, comp::Stats::default()); - state.write_component(entity, comp::Inputs::default()); - state.write_component(entity, comp::Actions::default()); + state.write_component(entity, comp::Control::default()); state.write_component(entity, comp::AnimationInfo::new()); state.write_component(entity, comp::phys::Pos(spawn_point)); state.write_component(entity, comp::phys::Vel(Vec3::zero())); @@ -210,25 +213,17 @@ impl Server { .collect::>(); for entity in todo_kill { - self.state - .ecs_mut() - .write_storage::() - .remove(entity); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); if let Some(client) = self.clients.get_mut(&entity) { client.force_state(ClientState::Dead); } else { - //self.state.ecs_mut().delete_entity_synced(entity); + self.state.ecs_mut().delete_entity_synced(entity); } } // Handle respawns let todo_respawn = ( &self.state.ecs().entities(), - &self.state.ecs().read_storage::(), + &self.state.ecs().read_storage::(), ) .join() .map(|(entity, _)| entity) @@ -237,12 +232,7 @@ impl Server { for entity in todo_respawn { if let Some(client) = self.clients.get_mut(&entity) { client.allow_state(ClientState::Character); - self.state - .ecs_mut() - .write_storage::() - .remove(entity); self.state.write_component(entity, comp::Stats::default()); - self.state.write_component(entity, comp::Actions::default()); self.state .ecs_mut() .write_storage::() @@ -319,6 +309,16 @@ impl Server { self.sync_clients(); // 7) Finish the tick, pass control back to the frontend. + + // Cleanup + let ecs = self.state.ecs_mut(); + for entity in ecs.entities().join() { + ecs.write_storage::().remove(entity); + ecs.write_storage::().remove(entity); + ecs.write_storage::().remove(entity); + ecs.write_storage::().remove(entity); + } + Ok(frontend_events) } @@ -442,6 +442,18 @@ impl Server { } ClientState::Pending => {} }, + ClientMsg::Attack => match client.client_state { + ClientState::Character => { + state.write_component(entity, comp::Attacking::start()); + } + _ => client.error_state(RequestStateError::Impossible), + }, + ClientMsg::Respawn => match client.client_state { + ClientState::Dead => { + state.write_component(entity, comp::Respawning); + } + _ => client.error_state(RequestStateError::Impossible), + }, ClientMsg::Chat(msg) => match client.client_state { ClientState::Connected => { client.error_state(RequestStateError::Impossible) @@ -452,18 +464,6 @@ impl Server { | ClientState::Character => new_chat_msgs.push((entity, msg)), ClientState::Pending => {} }, - ClientMsg::PlayerInputs(mut inputs) => match client.client_state { - ClientState::Character | ClientState::Dead => { - state - .ecs_mut() - .write_storage::() - .get_mut(entity) - .map(|s| { - s.events.append(&mut inputs.events); - }); - } - _ => client.error_state(RequestStateError::Impossible), - }, ClientMsg::PlayerAnimation(animation_info) => { match client.client_state { ClientState::Character => { diff --git a/voxygen/src/key_state.rs b/voxygen/src/key_state.rs index 909f1f3490..2921c4ce6c 100644 --- a/voxygen/src/key_state.rs +++ b/voxygen/src/key_state.rs @@ -5,8 +5,6 @@ pub struct KeyState { pub left: bool, pub up: bool, pub down: bool, - pub jump: bool, - pub glide: bool, } impl KeyState { @@ -16,8 +14,6 @@ impl KeyState { left: false, up: false, down: false, - jump: false, - glide: false, } } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 1563f2e017..c0c84d3fdf 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -109,7 +109,7 @@ impl PlayState for CharSelectionState { // Tick the client (currently only to keep the connection alive). self.client .borrow_mut() - .tick(comp::Inputs::default(), clock.get_last_delta()) + .tick(comp::Control::default(), clock.get_last_delta()) .expect("Failed to tick the client"); self.client.borrow_mut().cleanup(); diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 09db7596b2..75e3633d35 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -366,7 +366,8 @@ impl FigureMgr { .and_then(|stats| stats.hp.last_change) .map(|(change_by, time)| { Rgba::broadcast(1.0) - + Rgba::new(0.0, -1.0, -1.0, 0.0).map(|c| (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time)) as f32) + + Rgba::new(0.0, -1.0, -1.0, 0.0) + .map(|c| (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time)) as f32) }) .unwrap_or(Rgba::broadcast(1.0)); @@ -460,13 +461,17 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, actor, _) in ( + for (entity, actor, stats) in ( &ecs.entities(), &ecs.read_storage::(), - &ecs.read_storage::(), + &ecs.read_storage::(), // Just to make sure the entity is alive ) .join() { + if stats.is_dead() { + return; + } + match actor { comp::Actor::Character { body, .. } => { if let Some((locals, bone_consts)) = match body { diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index dbaa93db75..ca04c4f4d0 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -19,7 +19,6 @@ pub struct SessionState { scene: Scene, client: Rc>, key_state: KeyState, - input_events: Vec, hud: Hud, } @@ -34,7 +33,6 @@ impl SessionState { client, key_state: KeyState::new(), hud: Hud::new(window), - input_events: Vec::new(), } } } @@ -60,19 +58,11 @@ impl SessionState { let dir_vec = self.key_state.dir_vec(); let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1]; - // Take the input events. - let mut input_events = Vec::new(); - mem::swap(&mut self.input_events, &mut input_events); - - for event in self.client.borrow_mut().tick( - comp::Inputs { - move_dir, - jumping: self.key_state.jump, - gliding: self.key_state.glide, - events: input_events, - }, - dt, - )? { + for event in self + .client + .borrow_mut() + .tick(comp::Control { move_dir }, dt)? + { match event { client::Event::Chat(msg) => { self.hud.new_message(msg); @@ -136,21 +126,19 @@ impl PlayState for SessionState { return PlayStateResult::Shutdown; } // Attack key pressed - Event::InputUpdate(GameInput::Attack, state) => { - self.input_events.push(comp::InputEvent::Attack); - //self.input_events.push(comp::InputEvent::RequestRespawn); - }, + Event::InputUpdate(GameInput::Attack, true) => { + self.client.borrow_mut().attack(); + self.client.borrow_mut().respawn(); + } + Event::InputUpdate(GameInput::Jump, true) => { + self.client.borrow_mut().jump(); + } Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state, Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state, Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state, Event::InputUpdate(GameInput::MoveRight, state) => self.key_state.right = state, - Event::InputUpdate(GameInput::Glide, state) => self.key_state.glide = state, - Event::InputUpdate(GameInput::Jump, true) => { - self.input_events.push(comp::InputEvent::Jump); - self.key_state.jump = true; - } - Event::InputUpdate(GameInput::Jump, false) => { - self.key_state.jump = false; + Event::InputUpdate(GameInput::Glide, state) => { + self.client.borrow_mut().glide(state) } // Pass all other events to the scene diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 46ac859517..aa01158954 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -113,12 +113,18 @@ impl Window { key_map.insert(settings.controls.map, GameInput::Map); key_map.insert(settings.controls.bag, GameInput::Bag); key_map.insert(settings.controls.quest_log, GameInput::QuestLog); - key_map.insert(settings.controls.character_window, GameInput::CharacterWindow); + key_map.insert( + settings.controls.character_window, + GameInput::CharacterWindow, + ); key_map.insert(settings.controls.social, GameInput::Social); key_map.insert(settings.controls.spellbook, GameInput::Spellbook); key_map.insert(settings.controls.settings, GameInput::Settings); key_map.insert(settings.controls.help, GameInput::Help); - key_map.insert(settings.controls.toggle_interface, GameInput::ToggleInterface); + key_map.insert( + settings.controls.toggle_interface, + GameInput::ToggleInterface, + ); key_map.insert(settings.controls.toggle_debug, GameInput::ToggleDebug); key_map.insert(settings.controls.fullscreen, GameInput::Fullscreen); key_map.insert(settings.controls.screenshot, GameInput::Screenshot); @@ -184,11 +190,12 @@ impl Window { events.push(Event::Resize(Vec2::new(width as u32, height as u32))); } glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), - glutin::WindowEvent::MouseInput { button, state, .. } - if cursor_grabbed => - { + glutin::WindowEvent::MouseInput { button, state, .. } if cursor_grabbed => { if let Some(&game_input) = key_map.get(&KeyMouse::Mouse(button)) { - events.push(Event::InputUpdate(game_input, state == glutin::ElementState::Pressed)) + events.push(Event::InputUpdate( + game_input, + state == glutin::ElementState::Pressed, + )) } } glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode @@ -204,7 +211,10 @@ impl Window { glutin::ElementState::Pressed => take_screenshot = true, _ => {} }, - Some(&game_input) => events.push(Event::InputUpdate(game_input, input.state == glutin::ElementState::Pressed)), + Some(&game_input) => events.push(Event::InputUpdate( + game_input, + input.state == glutin::ElementState::Pressed, + )), _ => {} }, _ => {} From 746e286b5bde683532750c02bef72d1a64c39695 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 00:00:38 +0200 Subject: [PATCH 27/34] Fixes Former-commit-id: 0bbbcf187248dd192e7e9a226bcf5b496437d578 --- common/src/comp/stats.rs | 4 ++-- voxygen/src/hud/mod.rs | 2 +- voxygen/src/scene/figure.rs | 2 +- voxygen/src/session.rs | 2 -- voxygen/src/settings.rs | 4 ++-- voxygen/src/window.rs | 10 ++-------- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index a3c6ee49d1..f5a7494bb2 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -1,7 +1,7 @@ use crate::state::Time; use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct Health { pub current: u32, pub maximum: u32, @@ -15,7 +15,7 @@ impl Health { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct Stats { pub hp: Health, pub xp: u32, diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 4102a718fe..fff60328f6 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -694,7 +694,7 @@ impl Hud { self.show.debug = !self.show.debug; true } - Key::ToggleIngameUi => { + GameInput::ToggleIngameUi => { self.show.ingame = !self.show.ingame; true } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 75e3633d35..e6ccc2707c 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -397,7 +397,7 @@ impl FigureMgr { comp::Animation::Attack => character::AttackAnimation::update_skeleton( state.skeleton_mut(), time, - animation_history.time, + animation_info.time, ), comp::Animation::Gliding => { character::GlidingAnimation::update_skeleton( diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index ca04c4f4d0..5da08e22bd 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -125,14 +125,12 @@ impl PlayState for SessionState { Event::Close => { return PlayStateResult::Shutdown; } - // Attack key pressed Event::InputUpdate(GameInput::Attack, true) => { self.client.borrow_mut().attack(); self.client.borrow_mut().respawn(); } Event::InputUpdate(GameInput::Jump, true) => { self.client.borrow_mut().jump(); - } Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state, Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state, Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state, diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 14d625601d..a1aa91557c 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -41,7 +41,7 @@ pub struct ControlSettings { pub toggle_debug: KeyMouse, pub fullscreen: KeyMouse, pub screenshot: KeyMouse, - pub toggle_ingame_ui: VirtualKeyCode, + pub toggle_ingame_ui: KeyMouse, pub pan_sensitivity: f32, pub zoom_sensitivity: f32, pub attack: KeyMouse, @@ -100,7 +100,7 @@ impl Default for Settings { toggle_debug: KeyMouse::Key(VirtualKeyCode::F3), fullscreen: KeyMouse::Key(VirtualKeyCode::F11), screenshot: KeyMouse::Key(VirtualKeyCode::F4), - toggle_ingame_ui: VirtualKeyCode::F6, + toggle_ingame_ui: KeyMouse::Key(VirtualKeyCode::F6), pan_sensitivity: 1.0, zoom_sensitivity: 1.0, attack: KeyMouse::Mouse(MouseButton::Left), diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index aa01158954..22d119b80a 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -113,18 +113,12 @@ impl Window { key_map.insert(settings.controls.map, GameInput::Map); key_map.insert(settings.controls.bag, GameInput::Bag); key_map.insert(settings.controls.quest_log, GameInput::QuestLog); - key_map.insert( - settings.controls.character_window, - GameInput::CharacterWindow, - ); + key_map.insert(settings.controls.character_window, GameInput::CharacterWindow); key_map.insert(settings.controls.social, GameInput::Social); key_map.insert(settings.controls.spellbook, GameInput::Spellbook); key_map.insert(settings.controls.settings, GameInput::Settings); key_map.insert(settings.controls.help, GameInput::Help); - key_map.insert( - settings.controls.toggle_interface, - GameInput::ToggleInterface, - ); + key_map.insert(settings.controls.toggle_interface, GameInput::ToggleInterface); key_map.insert(settings.controls.toggle_debug, GameInput::ToggleDebug); key_map.insert(settings.controls.fullscreen, GameInput::Fullscreen); key_map.insert(settings.controls.screenshot, GameInput::Screenshot); From 79a0edad850783d81474976c422b192cf2a07668 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 00:04:40 +0200 Subject: [PATCH 28/34] Fix glider Former-commit-id: dbcdfef19b3cd428736e77176a958f128b7fe7ad --- client/src/lib.rs | 4 ---- voxygen/src/session.rs | 1 + voxygen/src/window.rs | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 02d024d0b4..f8001fa101 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -294,10 +294,6 @@ impl Client { .ecs_mut() .write_storage::() .remove(self.entity); - self.state - .ecs_mut() - .write_storage::() - .remove(self.entity); self.state .ecs_mut() .write_storage::() diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 5da08e22bd..4a3534fbb6 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -131,6 +131,7 @@ impl PlayState for SessionState { } Event::InputUpdate(GameInput::Jump, true) => { self.client.borrow_mut().jump(); + } Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state, Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state, Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state, diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 22d119b80a..8930ae7a4f 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -113,16 +113,25 @@ impl Window { key_map.insert(settings.controls.map, GameInput::Map); key_map.insert(settings.controls.bag, GameInput::Bag); key_map.insert(settings.controls.quest_log, GameInput::QuestLog); - key_map.insert(settings.controls.character_window, GameInput::CharacterWindow); + key_map.insert( + settings.controls.character_window, + GameInput::CharacterWindow, + ); key_map.insert(settings.controls.social, GameInput::Social); key_map.insert(settings.controls.spellbook, GameInput::Spellbook); key_map.insert(settings.controls.settings, GameInput::Settings); key_map.insert(settings.controls.help, GameInput::Help); - key_map.insert(settings.controls.toggle_interface, GameInput::ToggleInterface); + key_map.insert( + settings.controls.toggle_interface, + GameInput::ToggleInterface, + ); key_map.insert(settings.controls.toggle_debug, GameInput::ToggleDebug); key_map.insert(settings.controls.fullscreen, GameInput::Fullscreen); key_map.insert(settings.controls.screenshot, GameInput::Screenshot); - key_map.insert(settings.controls.toggle_ingame_ui, GameInput::ToggleIngameUi); + key_map.insert( + settings.controls.toggle_ingame_ui, + GameInput::ToggleIngameUi, + ); key_map.insert(settings.controls.attack, GameInput::Attack); Ok(Self { From d7d8888778dbb746b1bf0cf3f44eea08ea170e71 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 00:06:12 +0200 Subject: [PATCH 29/34] Fix chat-cli Former-commit-id: 8a6aad2dd199859d4e0731ecd766cef71fd14285 --- chat-cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs index 84c04cc27e..a080e6f9d6 100644 --- a/chat-cli/src/main.rs +++ b/chat-cli/src/main.rs @@ -23,7 +23,7 @@ fn main() { client.send_chat("Hello!".to_string()); loop { - let events = match client.tick(comp::Inputs::default(), clock.get_last_delta()) { + let events = match client.tick(comp::Control::default(), clock.get_last_delta()) { Ok(events) => events, Err(err) => { println!("Error: {:?}", err); From 148c015b386f439e15d1d6715fd96276b34b2e91 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 00:08:54 +0200 Subject: [PATCH 30/34] TODO comment for pet fix Former-commit-id: 747b926a92506887bb235e9e64e2c4f286d8b31b --- server/src/cmd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 93533b3b23..1c420cc701 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -212,7 +212,7 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .read_component_cloned::(entity) { Some(mut pos) => { - pos.0.x += 1.0; + pos.0.x += 1.0; // Temp fix TODO: Solve NaN issue with positions of pets server .create_npc( pos, From a18a8e0d158a3e3543a8a8e5a155f6d70f77fc60 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 00:34:24 +0200 Subject: [PATCH 31/34] Fix nametags showing on dead players (maybe) Former-commit-id: 94548e131ee7c94fc5546fa7410fc9694d1db68e --- voxygen/src/hud/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index fff60328f6..1599027ba6 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -305,10 +305,10 @@ impl Hud { let mut name_id_walker = self.ids.name_tags.walk(); let mut health_id_walker = self.ids.health_bars.walk(); let mut health_back_id_walker = self.ids.health_bar_backs.walk(); - for (pos, name) in (&entities, &pos, &actor, player.maybe()) + for (pos, name) in (&entities, &pos, &actor, &stats, player.maybe()) .join() - .filter(|(entity, _, _, _)| *entity != me) - .map(|(entity, pos, actor, player)| match actor { + .filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead()) + .map(|(entity, pos, actor, _, player)| match actor { comp::Actor::Character { name: char_name, .. } => { From cda253c3cffa9ab7cc9a7f660a4a236c35e1b56f Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 11:21:51 +0200 Subject: [PATCH 32/34] Make Failed to tick go back to the main screen and move to ron Former-commit-id: 14d4ab3cb9d964805a2f275b932e93cef9b72d38 --- .gitignore | 5 +- Cargo.lock | 118 ++++--------------------- voxygen/Cargo.toml | 3 +- voxygen/src/menu/char_selection/mod.rs | 8 +- voxygen/src/session.rs | 6 +- voxygen/src/settings.rs | 33 ++----- 6 files changed, 37 insertions(+), 136 deletions(-) diff --git a/.gitignore b/.gitignore index dcd92a42c3..c57b217423 100644 --- a/.gitignore +++ b/.gitignore @@ -15,10 +15,7 @@ *.code-workspace # Veloren -voxygen/keybinds.toml -settings.toml -voxygen/settings/ *.rar *.log run.sh -screenshots \ No newline at end of file +screenshots diff --git a/Cargo.lock b/Cargo.lock index d113f9fc0e..2d72718ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,6 +139,14 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bincode" version = "1.1.4" @@ -349,21 +357,6 @@ name = "color_quant" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "config" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", - "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "conrod_core" version = "0.63.0" @@ -1214,11 +1207,6 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "jpeg-decoder" version = "0.1.15" @@ -1304,15 +1292,6 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "linked-hash-map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "linked-hash-map" version = "0.5.2" @@ -2133,9 +2112,14 @@ dependencies = [ ] [[package]] -name = "rust-ini" -version = "0.13.0" +name = "ron" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "rustc-demangle" @@ -2174,11 +2158,6 @@ dependencies = [ "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ryu" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "same-file" version = "1.0.4" @@ -2239,11 +2218,6 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" version = "1.0.91" @@ -2252,18 +2226,6 @@ dependencies = [ "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde-hjson" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_derive" version = "1.0.91" @@ -2274,24 +2236,6 @@ dependencies = [ "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde_json" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_test" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "shared_library" version = "0.1.9" @@ -2539,14 +2483,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tuple_utils" version = "0.2.0" @@ -2669,7 +2605,6 @@ name = "veloren-voxygen" version = "0.2.0" dependencies = [ "backtrace 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2691,11 +2626,11 @@ dependencies = [ "portpicker 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rodio 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", "veloren-client 0.2.0", "veloren-common 0.2.0", @@ -2903,14 +2838,6 @@ name = "xml-rs" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "yaml-rust" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" @@ -2929,6 +2856,7 @@ dependencies = [ "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum backtrace 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "70af6de4789ac39587f100176ac7f704531e9e534b0f8676f658b3d909ce9a94" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" "checksum bindgen 0.32.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b242e11a8f446f5fc7b76b37e81d737cabca562a927bd33766dac55b5f1177f" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" @@ -2954,7 +2882,6 @@ dependencies = [ "checksum cocoa 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0c23085dde1ef4429df6e5896b89356d35cdd321fb43afe3e378d010bb5adc6" "checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" -"checksum config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6" "checksum conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)" = "" "checksum conrod_derive 0.63.0 (git+https://gitlab.com/veloren/conrod.git)" = "" "checksum conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)" = "" @@ -3041,7 +2968,6 @@ dependencies = [ "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum instant 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6706e8fb9de9be6143801a75747fa2209855b13d74ee994e30d86b38afdf77f" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" @@ -3054,7 +2980,6 @@ dependencies = [ "checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" -"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -3147,12 +3072,11 @@ dependencies = [ "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum rodio 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10cb47941163cb747978d13a5c1b5c8fcd17f501817c4b77b9d69aed9ea240bc" -"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" +"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "25951e85bb2647960969f72c559392245a5bd07446a589390bf427dda31cdc4a" -"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scan_fmt 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b87497427f9fbe539ee6b9626f5a5e899331fdf1c1d62f14c637a462969db30" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" @@ -3161,12 +3085,8 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" -"checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" "checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f" -"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" -"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" "checksum shred 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea122e6133568144fcfb5888737d4ac776ebc959f989dd65b907136ac22bfed" "checksum shred-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcf34e5e5302d3024aba7afc291f6d1ca7573ed035d3c0796976ba3f10691a1" @@ -3195,7 +3115,6 @@ dependencies = [ "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfecd7bb8f0a3e96b3b31c46af2677a55a588767c0091f484601424fcb20e7e" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" @@ -3226,4 +3145,3 @@ dependencies = [ "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" -"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index a9aeb3c753..75d7117537 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -40,10 +40,9 @@ lazy_static = "1.1" log = "0.4" dot_vox = "4.0" image = "0.21" -config = "0.9" serde = "1.0" serde_derive = "1.0" -toml = "0.4" +ron = "0.5.1" guillotiere = "0.4" fnv = "1.0" simplelog = "0.5" diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index c0c84d3fdf..d99e739831 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -107,10 +107,14 @@ impl PlayState for CharSelectionState { .render(global_state.window.renderer_mut(), self.scene.globals()); // Tick the client (currently only to keep the connection alive). - self.client + if let Err(err) = self + .client .borrow_mut() .tick(comp::Control::default(), clock.get_last_delta()) - .expect("Failed to tick the client"); + { + log::error!("Failed to tick the scene: {:?}", err); + return PlayStateResult::Pop; + } self.client.borrow_mut().cleanup(); // Finish the frame. diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 4a3534fbb6..b3d1d6372a 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -148,8 +148,10 @@ impl PlayState for SessionState { } // Perform an in-game tick. - self.tick(clock.get_last_delta()) - .expect("Failed to tick the scene!"); + if let Err(err) = self.tick(clock.get_last_delta()) { + log::error!("Failed to tick the scene: {:?}", err); + return PlayStateResult::Pop; + } // Maintain global state global_state.maintain(); diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index a1aa91557c..d92d5bd626 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -1,10 +1,8 @@ use crate::window::KeyMouse; -use config::{Config, ConfigError}; use directories::ProjectDirs; use glutin::{MouseButton, VirtualKeyCode}; use serde_derive::{Deserialize, Serialize}; use std::{fs, io::prelude::*, path::PathBuf}; -use toml; /// `Settings` contains everything that can be configured in the Settings.toml file. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -129,28 +127,11 @@ impl Settings { let path = Settings::get_settings_path(); - let mut config = Config::new(); - - config - .merge( - Config::try_from(&default_settings) - .expect("Default settings struct could not be converted to Config!"), - ) - .unwrap(); - - // TODO: Log errors here. - // If merge or try_into fail, use the default settings. - match config.merge::>(path.into()) { - Ok(_) => match config.try_into() { - Ok(settings) => settings, - Err(_) => default_settings, - }, - Err(_) => { - // Maybe the file didn't exist. - // TODO: Handle this result. - default_settings.save_to_file(); - default_settings - } + // If file doesn't exist, use the default settings. + if let Ok(file) = fs::File::open(path) { + ron::de::from_reader(file).expect("Error parsing settings") + } else { + Self::default() } } @@ -162,7 +143,7 @@ impl Settings { } let mut config_file = fs::File::create(path)?; - let s: &str = &toml::to_string_pretty(self).unwrap(); + let s: &str = &ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap(); config_file.write_all(s.as_bytes()).unwrap(); Ok(()) } @@ -172,7 +153,7 @@ impl Settings { ProjectDirs::from("net", "veloren", "voxygen").expect("No home directory defined!"); let path = proj_dirs.config_dir(); path.join("settings"); - let path = path.with_extension("toml"); + let path = path.with_extension("ron"); path } } From 64b00f41f40997b75fa97c40ff7b4398b2101635 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 16:04:44 +0200 Subject: [PATCH 33/34] Fix invisible chars Former-commit-id: cbb93e0511100b9b66f9ea22451c99a69b50b19c --- common/src/comp/animation.rs | 4 +-- common/src/sys/inputs.rs | 3 +- server/src/lib.rs | 61 +++++++++++++++++++++++++----------- voxygen/src/hud/mod.rs | 20 ++++++------ voxygen/src/scene/figure.rs | 8 +++-- voxygen/src/session.rs | 9 +++--- 6 files changed, 64 insertions(+), 41 deletions(-) diff --git a/common/src/comp/animation.rs b/common/src/comp/animation.rs index 72c8bc56c4..c31761424d 100644 --- a/common/src/comp/animation.rs +++ b/common/src/comp/animation.rs @@ -17,8 +17,8 @@ pub struct AnimationInfo { pub changed: bool, } -impl AnimationInfo { - pub fn new() -> Self { +impl Default for AnimationInfo { + fn default() -> Self { Self { animation: Animation::Idle, time: 0.0, diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 6f0a4f267b..1f3c74abb3 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -127,7 +127,7 @@ impl<'a> System<'a> for Sys { let last = animation_infos .get_mut(entity) .cloned() - .unwrap_or(AnimationInfo::new()); + .unwrap_or(AnimationInfo::default()); let changed = last.animation != animation; animation_infos.insert( @@ -149,6 +149,7 @@ impl<'a> System<'a> for Sys { { // Check if it is a hit if entity != b + && !stat_b.is_dead() && pos.0.distance_squared(pos_b.0) < 50.0 && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 { diff --git a/server/src/lib.rs b/server/src/lib.rs index 99f3d118b8..b9e3fb4ce9 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -139,6 +139,7 @@ impl Server { .with(comp::Control::default()) .with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Dir(Vec3::unit_y())) + .with(comp::AnimationInfo::default()) .with(comp::Actor::Character { name, body }) .with(comp::Stats::default()) } @@ -155,7 +156,7 @@ impl Server { state.write_component(entity, comp::Actor::Character { name, body }); state.write_component(entity, comp::Stats::default()); state.write_component(entity, comp::Control::default()); - state.write_component(entity, comp::AnimationInfo::new()); + state.write_component(entity, comp::AnimationInfo::default()); state.write_component(entity, comp::phys::Pos(spawn_point)); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); @@ -569,18 +570,35 @@ impl Server { // Save player metadata (for example the username). state.write_component(entity, player); - // Sync logical information other players have authority over, not the server. - for (other_entity, &uid, &animation_info) in ( + // Sync physics + for (entity, &uid, &pos, &vel, &dir) in ( &state.ecs().entities(), - &state.ecs().read_storage::(), + &state.ecs().read_storage::(), + &state.ecs().read_storage::(), + &state.ecs().read_storage::(), + &state.ecs().read_storage::(), + ) + .join() + { + client.notify(ServerMsg::EntityPhysics { + entity: uid.into(), + pos, + vel, + dir, + }); + } + + // Sync animations + for (entity, &uid, &animation_info) in ( + &state.ecs().entities(), + &state.ecs().read_storage::(), &state.ecs().read_storage::(), ) .join() { - // Animation client.notify(ServerMsg::EntityAnimation { entity: uid.into(), - animation_info: animation_info, + animation_info: animation_info.clone(), }); } @@ -594,7 +612,7 @@ impl Server { self.clients .notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); - // Sync 'physical' state. + // Sync physics for (entity, &uid, &pos, &vel, &dir, force_update) in ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), @@ -616,27 +634,32 @@ impl Server { }; match force_update { - Some(_) => self.clients.notify_ingame(msg), - None => self.clients.notify_ingame_except(entity, msg), + Some(_) => self.clients.notify_registered(msg), + None => self.clients.notify_registered_except(entity, msg), } } - // Sync animation. - for (entity, &uid, &animation_info) in ( + // Sync animations + for (entity, &uid, &animation_info, force_update) in ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), + self.state + .ecs() + .read_storage::() + .maybe(), ) .join() { - if animation_info.changed { - self.clients.notify_ingame_except( - entity, - ServerMsg::EntityAnimation { - entity: uid.into(), - animation_info: animation_info.clone(), - }, - ); + if animation_info.changed || force_update.is_some() { + let msg = ServerMsg::EntityAnimation { + entity: uid.into(), + animation_info: animation_info.clone(), + }; + match force_update { + Some(_) => self.clients.notify_registered(msg), + None => self.clients.notify_registered_except(entity, msg), + } } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 1599027ba6..032e214275 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -335,15 +335,10 @@ impl Hud { .resolution(100.0) .set(id, ui_widgets); } - for (pos, hp) in (&entities, &pos, &stats) + + for (entity, pos, stats) in (&entities, &pos, &stats) .join() - .filter_map(|(entity, pos, stats)| { - if entity != me { - Some((pos.0, stats.hp)) - } else { - None - } - }) + .filter(|(entity, _, stats)| *entity != me && !stats.is_dead()) { let back_id = health_back_id_walker.next( &mut self.ids.health_bar_backs, @@ -356,17 +351,20 @@ impl Hud { // Healh Bar Rectangle::fill_with([120.0, 8.0], Color::Rgba(0.3, 0.3, 0.3, 0.5)) .x_y(0.0, -25.0) - .position_ingame(pos + Vec3::new(0.0, 0.0, 3.0)) + .position_ingame(pos.0 + Vec3::new(0.0, 0.0, 3.0)) .resolution(100.0) .set(back_id, ui_widgets); // Filling Rectangle::fill_with( - [120.0 * (hp.current as f64 / hp.maximum as f64), 8.0], + [ + 120.0 * (stats.hp.current as f64 / stats.hp.maximum as f64), + 8.0, + ], HP_COLOR, ) .x_y(0.0, -25.0) - .position_ingame(pos + Vec3::new(0.0, 0.0, 3.0)) + .position_ingame(pos.0 + Vec3::new(0.0, 0.0, 3.0)) .resolution(100.0) .set(bar_id, ui_widgets); } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index e6ccc2707c..60bf43c0ad 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -461,15 +461,15 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, actor, stats) in ( + for (entity, actor, stat) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), // Just to make sure the entity is alive ) .join() { - if stats.is_dead() { - return; + if stat.is_dead() { + //return; } match actor { @@ -487,6 +487,8 @@ impl FigureMgr { let model = self.model_cache.get_or_create_model(renderer, *body, tick); renderer.render_figure(model, globals, locals, bone_consts); + } else { + panic!(); } } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index b3d1d6372a..1b51b9d4f0 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -156,10 +156,6 @@ impl PlayState for SessionState { // Maintain global state global_state.maintain(); - // Maintain the scene. - self.scene - .maintain(global_state.window.renderer_mut(), &self.client.borrow()); - // extract HUD events ensuring the client borrow gets dropped let hud_events = self.hud.maintain( &self.client.borrow(), @@ -201,7 +197,10 @@ impl PlayState for SessionState { } } } - {} + + // Maintain the scene. + self.scene + .maintain(global_state.window.renderer_mut(), &self.client.borrow()); // Render the session. self.render(global_state.window.renderer_mut()); From f0397f1a32d6d59d676c71186e07dcbc0aaaf680 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sun, 26 May 2019 16:11:30 +0200 Subject: [PATCH 34/34] log::error instead of panic Former-commit-id: 802f81425869698a95654d423fef93136617cb5f --- voxygen/src/scene/figure.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 60bf43c0ad..fb57e018dd 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -469,7 +469,7 @@ impl FigureMgr { .join() { if stat.is_dead() { - //return; + return; } match actor { @@ -488,7 +488,7 @@ impl FigureMgr { renderer.render_figure(model, globals, locals, bone_consts); } else { - panic!(); + log::error!("Body has no saved figure"); } } }