diff --git a/client/src/lib.rs b/client/src/lib.rs index 285017027f..1dd3cc0e1c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -100,12 +100,6 @@ impl Client { // We reduce the thread count by 1 to keep rendering smooth thread_pool.set_num_threads((num_cpus::get() - 1).max(1)); - // Set client-only components - let _ = state - .ecs_mut() - .write_storage() - .insert(entity, comp::AnimationInfo::default()); - Ok(Self { client_state, thread_pool, @@ -279,10 +273,30 @@ impl Client { // 2) Build up a list of events for this frame, to be passed to the frontend. let mut frontend_events = Vec::new(); + // Prepare for new events + { + let ecs = self.state.ecs_mut(); + for (entity, _) in (&ecs.entities(), &ecs.read_storage::()).join() { + let mut last_character_states = + ecs.write_storage::>(); + if let Some(client_character_state) = + ecs.read_storage::().get(entity) + { + if last_character_states + .get(entity) + .map(|&l| !client_character_state.is_same_state(&l.0)) + .unwrap_or(true) + { + let _ = last_character_states + .insert(entity, comp::Last(*client_character_state)); + } + } + } + } // Handle new messages from the server. frontend_events.append(&mut self.handle_new_messages()?); - // 3) + // 3) Update client local data // 4) Tick the client's LocalState self.state.tick(dt); @@ -395,7 +409,6 @@ impl Client { } // 7) Finish the tick, pass control back to the frontend. - self.tick += 1; Ok(frontend_events) } diff --git a/common/src/comp/animation.rs b/common/src/comp/animation.rs deleted file mode 100644 index ee4fc69da4..0000000000 --- a/common/src/comp/animation.rs +++ /dev/null @@ -1,35 +0,0 @@ -use specs::{Component, FlaggedStorage}; -use specs_idvs::IDVStorage; - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum Animation { - Idle, - Run, - Jump, - Gliding, - Attack, - Block, - Roll, - Crun, - Cidle, - Cjump, -} - -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] -pub struct AnimationInfo { - pub animation: Animation, - pub time: f64, -} - -impl Default for AnimationInfo { - fn default() -> Self { - Self { - animation: Animation::Idle, - time: 0.0, - } - } -} - -impl Component for AnimationInfo { - type Storage = FlaggedStorage>; -} diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index c9d5c55b17..fb34afefd5 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -63,6 +63,20 @@ pub struct CharacterState { pub action: ActionState, } +impl CharacterState { + pub fn is_same_movement(&self, other: &Self) -> bool { + // Check if enum item is the same without looking at the inner data + std::mem::discriminant(&self.movement) == std::mem::discriminant(&other.movement) + } + pub fn is_same_action(&self, other: &Self) -> bool { + // Check if enum item is the same without looking at the inner data + std::mem::discriminant(&self.action) == std::mem::discriminant(&other.action) + } + pub fn is_same_state(&self, other: &Self) -> bool { + self.is_same_movement(other) && self.is_same_action(other) + } +} + impl Default for CharacterState { fn default() -> Self { Self { diff --git a/common/src/comp/last.rs b/common/src/comp/last.rs index 2ec18b6712..94561f1c5d 100644 --- a/common/src/comp/last.rs +++ b/common/src/comp/last.rs @@ -7,9 +7,3 @@ pub struct Last(pub C); impl Component for Last { type Storage = VecStorage; } - -impl PartialEq for Last { - fn eq(&self, other: &C) -> bool { - self.0 == *other - } -} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 18bb53be8b..450b67b271 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,6 +1,5 @@ mod admin; mod agent; -mod animation; mod body; mod character_state; mod controller; @@ -15,7 +14,6 @@ mod visual; // Reexports pub use admin::Admin; pub use agent::Agent; -pub use animation::{Animation, AnimationInfo}; pub use body::{humanoid, object, quadruped, quadruped_medium, Body}; pub use character_state::{ActionState, CharacterState, MovementState}; pub use controller::Controller; diff --git a/common/src/state.rs b/common/src/state.rs index fbe80d206b..43c9d5a9ba 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -133,9 +133,6 @@ impl State { ecs.register::(); ecs.register::(); - // Register client-local components - ecs.register::(); - // Register server-local components ecs.register::>(); ecs.register::>(); diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs deleted file mode 100644 index fde92932c3..0000000000 --- a/common/src/sys/animation.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{ - comp::{ - ActionState::*, Animation, AnimationInfo, CharacterState, MovementState::*, PhysicsState, - Stats, - }, - state::DeltaTime, -}; -use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; -use std::fmt::Debug; - -/// This system will apply the animation that fits best to the users actions -pub struct Sys; -impl<'a> System<'a> for Sys { - type SystemData = ( - Entities<'a>, - Read<'a, DeltaTime>, - ReadStorage<'a, Stats>, - ReadStorage<'a, CharacterState>, - ReadStorage<'a, PhysicsState>, - WriteStorage<'a, AnimationInfo>, - ); - - fn run( - &mut self, - (entities, dt, stats, character_states, physics_states, mut animation_infos): Self::SystemData, - ) { - for (entity, stats, character, physics) in - (&entities, &stats, &character_states, &physics_states).join() - { - if stats.is_dead { - continue; - } - - let animation = match (physics.on_ground, &character.movement, &character.action) { - (_, Roll { .. }, Idle) => Animation::Roll, - (true, Stand, Idle) => Animation::Idle, - (true, Run, Idle) => Animation::Run, - (false, Jump, Idle) => Animation::Jump, - (true, Stand, Wield { .. }) => Animation::Cidle, - (true, Run, Wield { .. }) => Animation::Crun, - (false, Jump, Wield { .. }) => Animation::Cjump, - (_, Glide, Idle) => Animation::Gliding, - (_, _, Attack { .. }) => Animation::Attack, - (_, _, Block { .. }) => Animation::Block, - // Impossible animation (Caused by missing animations or syncing delays) - _ => Animation::Gliding, - }; - - let new_time = animation_infos - .get(entity) - .filter(|i| i.animation == animation) - .map(|i| i.time + f64::from(dt.0)); - - let _ = animation_infos.insert( - entity, - AnimationInfo { - animation, - time: new_time.unwrap_or(0.0), - }, - ); - } - } -} diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index d1d7895e08..d177fde4b2 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -1,5 +1,4 @@ pub mod agent; -pub mod animation; mod cleanup; pub mod combat; pub mod controller; @@ -16,7 +15,6 @@ const CONTROLLER_SYS: &str = "controller_sys"; const PHYS_SYS: &str = "phys_sys"; const MOVEMENT_SYS: &str = "movement_sys"; const COMBAT_SYS: &str = "combat_sys"; -const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; const CLEANUP_SYS: &str = "cleanup_sys"; @@ -26,7 +24,6 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]); dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[PHYS_SYS]); dispatch_builder.add(combat::Sys, COMBAT_SYS, &[CONTROLLER_SYS]); - dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[MOVEMENT_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); - dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[STATS_SYS, ANIMATION_SYS]); + dispatch_builder.add(cleanup::Sys, CLEANUP_SYS, &[STATS_SYS, MOVEMENT_SYS]); } diff --git a/common/src/sys/movement.rs b/common/src/sys/movement.rs index d89b89b2c5..3d2b767dfd 100644 --- a/common/src/sys/movement.rs +++ b/common/src/sys/movement.rs @@ -20,6 +20,8 @@ const HUMANOID_AIR_SPEED: f32 = 100.0; const ROLL_SPEED: f32 = 13.0; const GLIDE_ACCEL: f32 = 15.0; const GLIDE_SPEED: f32 = 45.0; +const BLOCK_ACCEL: f32 = 30.0; +const BLOCK_SPEED: f32 = 75.0; // Gravity is 9.81 * 4, so this makes gravity equal to .15 const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95; @@ -80,6 +82,14 @@ impl<'a> System<'a> for Sys { .try_normalized() .unwrap_or(Vec2::from(vel.0).try_normalized().unwrap_or_default()) * ROLL_SPEED + } + if character.action.is_block() || character.action.is_attack() { + vel.0 += Vec2::broadcast(dt.0) + * controller.move_dir + * match (physics.on_ground) { + (true) if vel.0.magnitude_squared() < BLOCK_SPEED.powf(2.0) => BLOCK_ACCEL, + _ => 0.0, + } } else { // Move player according to move_dir vel.0 += Vec2::broadcast(dt.0) diff --git a/server/src/lib.rs b/server/src/lib.rs index 0be77d38d9..c1ebb8d86b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -243,6 +243,8 @@ impl Server { let state = &mut self.state; let clients = &mut self.clients; + let mut todo_remove = None; + match event { ServerEvent::Explosion { pos, radius } => { const RAYS: usize = 500; @@ -306,23 +308,21 @@ impl Server { clients.notify_registered(ServerMsg::kill(msg)); } - { - // Give EXP to the client - let mut stats = ecs.write_storage::(); + // Give EXP to the client + let mut stats = ecs.write_storage::(); - if let Some(entity_stats) = stats.get(entity).cloned() { - if let comp::HealthSource::Attack { by } = cause { - ecs.entity_from_uid(by.into()).map(|attacker| { - if let Some(attacker_stats) = stats.get_mut(attacker) { - // TODO: Discuss whether we should give EXP by Player Killing or not. - attacker_stats.exp.change_by( - (entity_stats.health.maximum() as f64 / 10.0 - + entity_stats.level.level() as f64 * 10.0) - as i64, - ); - } - }); - } + if let Some(entity_stats) = stats.get(entity).cloned() { + if let comp::HealthSource::Attack { by } = cause { + ecs.entity_from_uid(by.into()).map(|attacker| { + if let Some(attacker_stats) = stats.get_mut(attacker) { + // TODO: Discuss whether we should give EXP by Player Killing or not. + attacker_stats.exp.change_by( + (entity_stats.health.maximum() as f64 / 10.0 + + entity_stats.level.level() as f64 * 10.0) + as i64, + ); + } + }); } } @@ -331,7 +331,7 @@ impl Server { let _ = ecs.write_storage().insert(entity, comp::ForceUpdate); client.force_state(ClientState::Dead); } else { - let _ = state.ecs_mut().delete_entity_synced(entity); + todo_remove = Some(entity.clone()); } } @@ -356,6 +356,10 @@ impl Server { } } } + + if let Some(entity) = todo_remove { + let _ = state.ecs_mut().delete_entity_synced(entity); + } } } @@ -1101,7 +1105,7 @@ impl Server { if let Some(client_pos) = ecs.read_storage::().get(entity) { if last_pos .get(entity) - .map(|&l| l != *client_pos) + .map(|&l| l.0 != *client_pos) .unwrap_or(true) { let _ = last_pos.insert(entity, comp::Last(*client_pos)); @@ -1119,7 +1123,7 @@ impl Server { if let Some(client_vel) = ecs.read_storage::().get(entity) { if last_vel .get(entity) - .map(|&l| l != *client_vel) + .map(|&l| l.0 != *client_vel) .unwrap_or(true) { let _ = last_vel.insert(entity, comp::Last(*client_vel)); @@ -1137,7 +1141,7 @@ impl Server { if let Some(client_ori) = ecs.read_storage::().get(entity) { if last_ori .get(entity) - .map(|&l| l != *client_ori) + .map(|&l| l.0 != *client_ori) .unwrap_or(true) { let _ = last_ori.insert(entity, comp::Last(*client_ori)); @@ -1157,7 +1161,7 @@ impl Server { { if last_character_state .get(entity) - .map(|&l| l != *client_character_state) + .map(|&l| !client_character_state.is_same_state(&l.0)) .unwrap_or(true) { let _ = diff --git a/voxygen/src/anim/character/block.rs b/voxygen/src/anim/character/block.rs index e62654ec0e..f3ff71c066 100644 --- a/voxygen/src/anim/character/block.rs +++ b/voxygen/src/anim/character/block.rs @@ -107,23 +107,23 @@ impl Animation for BlockAnimation { next.weapon.scale = Vec3::one(); } Tool::Hammer => { - next.l_hand.offset = Vec3::new(-5.5, 9.0, 5.5); + next.l_hand.offset = Vec3::new(-5.5, 10.0, 9.5); next.l_hand.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.57) + * Quaternion::rotation_y(-1.35) * Quaternion::rotation_z(0.5); next.l_hand.scale = Vec3::one() * 1.01; - next.r_hand.offset = Vec3::new(8.4, 9.3, 5.5); + next.r_hand.offset = Vec3::new(8.4, 9.3, 7.5); next.r_hand.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.57) + * Quaternion::rotation_y(-1.35) * Quaternion::rotation_z(0.5); next.r_hand.scale = Vec3::one() * 1.01; next.weapon.offset = Vec3::new( 7.0 + skeleton_attr.weapon_x, 10.75 + skeleton_attr.weapon_y, - 5.5, + 7.5, ); next.weapon.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.57) + * Quaternion::rotation_y(-1.35) * Quaternion::rotation_z(0.5); next.weapon.scale = Vec3::one(); } @@ -224,13 +224,13 @@ impl Animation for BlockAnimation { next.weapon.scale = Vec3::one(); } } - next.l_foot.offset = Vec3::new(-3.4, 0.3, 8.0 + wave_ultra_slow_cos * 0.1); - next.l_foot.ori = Quaternion::rotation_x(-0.3); - next.l_foot.scale = Vec3::one(); + //next.l_foot.offset = Vec3::new(-3.4, 0.3, 8.0 + wave_ultra_slow_cos * 0.1); + //next.l_foot.ori = Quaternion::rotation_x(-0.3); + //next.l_foot.scale = Vec3::one(); - next.r_foot.offset = Vec3::new(3.4, 1.2, 8.0 + wave_ultra_slow * 0.1); - next.r_foot.ori = Quaternion::rotation_x(0.3); - next.r_foot.scale = Vec3::one(); + //next.r_foot.offset = Vec3::new(3.4, 1.2, 8.0 + wave_ultra_slow * 0.1); + //next.r_foot.ori = Quaternion::rotation_x(0.3); + //next.r_foot.scale = Vec3::one(); next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7); next.l_shoulder.ori = Quaternion::rotation_x(0.0); diff --git a/voxygen/src/anim/character/blockidle.rs b/voxygen/src/anim/character/blockidle.rs new file mode 100644 index 0000000000..a2e5c4f839 --- /dev/null +++ b/voxygen/src/anim/character/blockidle.rs @@ -0,0 +1,252 @@ +use super::{ + super::{Animation, SkeletonAttr}, + CharacterSkeleton, +}; +use common::comp::item::Tool; +use std::{f32::consts::PI, ops::Mul}; +use vek::*; + +pub struct Input { + pub attack: bool, +} +pub struct BlockIdleAnimation; + +impl Animation for BlockIdleAnimation { + type Skeleton = CharacterSkeleton; + type Dependency = f64; + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: f64, + anim_time: f64, + skeleton_attr: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave_ultra_slow = (anim_time as f32 * 3.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 3.0 + PI).cos(); + let wave_slow_cos = (anim_time as f32 * 6.0 + PI).cos(); + + let _head_look = Vec2::new( + ((global_time + anim_time) as f32 / 1.5) + .floor() + .mul(7331.0) + .sin() + * 0.3, + ((global_time + anim_time) as f32 / 1.5) + .floor() + .mul(1337.0) + .sin() + * 0.15, + ); + next.head.offset = Vec3::new( + 0.0 + skeleton_attr.neck_right + wave_slow_cos * 0.2, + 1.0 + skeleton_attr.neck_forward, + skeleton_attr.neck_height + 13.5 + wave_ultra_slow * 0.2, + ); + next.head.ori = Quaternion::rotation_x(-0.25); + next.head.scale = Vec3::one() * 1.01 * skeleton_attr.head_scale; + + next.chest.offset = Vec3::new(0.0 + wave_slow_cos * 0.2, 0.0, 5.0 + wave_ultra_slow * 0.2); + next.chest.ori = + Quaternion::rotation_x(-0.15) * Quaternion::rotation_y(wave_ultra_slow_cos * 0.01); + next.chest.scale = Vec3::one(); + + next.belt.offset = Vec3::new(0.0 + wave_slow_cos * 0.2, 0.0, 3.0 + wave_ultra_slow * 0.2); + next.belt.ori = + Quaternion::rotation_x(0.0) * Quaternion::rotation_y(wave_ultra_slow_cos * 0.008); + next.belt.scale = Vec3::one() * 1.01; + + next.shorts.offset = Vec3::new(0.0 + wave_slow_cos * 0.2, 0.0, 1.0 + wave_ultra_slow * 0.2); + next.shorts.ori = Quaternion::rotation_x(0.1); + next.shorts.scale = Vec3::one(); + + match Tool::Hammer { + //TODO: Inventory + Tool::Sword => { + next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0 + wave_ultra_slow * 1.0); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x, + 4.5 + skeleton_attr.weapon_y, + 0.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + Tool::Axe => { + next.l_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.5 + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.0 + wave_ultra_slow_cos * 0.5, + -2.0 + wave_ultra_slow * 1.0, + ); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x, + 4.5 + skeleton_attr.weapon_y, + 0.0 + wave_ultra_slow * 1.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + Tool::Hammer => { + next.l_hand.offset = Vec3::new(-5.5, 10.0 + wave_ultra_slow * 2.0, 9.5); + next.l_hand.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.35) + * Quaternion::rotation_z(0.5); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(8.4, 9.3 + wave_ultra_slow * 2.0, 7.5); + next.r_hand.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.35) + * Quaternion::rotation_z(0.5); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + 7.0 + skeleton_attr.weapon_x, + 10.75 + skeleton_attr.weapon_y + wave_ultra_slow * 2.0, + 7.5, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.35) + * Quaternion::rotation_z(0.5); + next.weapon.scale = Vec3::one(); + } + Tool::Staff => { + next.l_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.5 + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.0 + wave_ultra_slow_cos * 0.5, + -2.0 + wave_ultra_slow * 1.0, + ); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0, + 4.5 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + Tool::SwordShield => { + next.l_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.5 + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.0 + wave_ultra_slow_cos * 0.5, + -2.0 + wave_ultra_slow * 1.0, + ); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0, + 4.5 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + Tool::Bow => { + next.l_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.5 + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.0 + wave_ultra_slow_cos * 0.5, + -2.0 + wave_ultra_slow * 1.0, + ); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0, + 4.5 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + Tool::Daggers => { + next.l_hand.offset = Vec3::new( + -6.0 + wave_ultra_slow_cos * 1.0, + 3.5 + wave_ultra_slow_cos * 0.5, + 0.0 + wave_ultra_slow * 1.0, + ); + next.l_hand.ori = Quaternion::rotation_x(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0); + next.r_hand.ori = Quaternion::rotation_x(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + -6.0 + skeleton_attr.weapon_x, + 4.5 + skeleton_attr.weapon_y, + 0.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.weapon.scale = Vec3::one(); + } + } + next.l_foot.offset = Vec3::new(-3.4, 0.3, 8.0 + wave_ultra_slow_cos * 0.1); + next.l_foot.ori = Quaternion::rotation_x(-0.3); + next.l_foot.scale = Vec3::one(); + + next.r_foot.offset = Vec3::new(3.4, 1.2, 8.0 + wave_ultra_slow * 0.1); + next.r_foot.ori = Quaternion::rotation_x(0.3); + next.r_foot.scale = Vec3::one(); + + next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7); + next.l_shoulder.ori = Quaternion::rotation_x(0.0); + next.l_shoulder.scale = Vec3::one() * 1.1; + + next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7); + next.r_shoulder.ori = Quaternion::rotation_x(0.0); + next.r_shoulder.scale = Vec3::one() * 1.1; + + next.draw.offset = Vec3::new(0.0, 5.0, 0.0); + next.draw.ori = Quaternion::rotation_y(0.0); + next.draw.scale = Vec3::one() * 0.0; + + next.torso.offset = Vec3::new(0.0, -0.2, 0.1) * skeleton_attr.scaler; + next.torso.ori = Quaternion::rotation_x(0.0); + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + + next + } +} diff --git a/voxygen/src/anim/character/crun.rs b/voxygen/src/anim/character/crun.rs index 26cbe654fb..def3c9c8d5 100644 --- a/voxygen/src/anim/character/crun.rs +++ b/voxygen/src/anim/character/crun.rs @@ -7,9 +7,9 @@ use std::f32::consts::PI; use std::ops::Mul; use vek::*; -pub struct CrunAnimation; +pub struct WieldAnimation; -impl Animation for CrunAnimation { +impl Animation for WieldAnimation { type Skeleton = CharacterSkeleton; type Dependency = (f32, f64); @@ -40,26 +40,6 @@ impl Animation for CrunAnimation { * 0.1, ); - next.head.offset = Vec3::new( - 0.0, - 0.0 + skeleton_attr.neck_forward, - skeleton_attr.neck_height + 15.0 + wave_cos * 1.3, - ); - next.head.ori = Quaternion::rotation_z(head_look.x + wave * 0.1) - * Quaternion::rotation_x(head_look.y + 0.35); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; - - next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1); - next.chest.ori = Quaternion::rotation_z(wave * 0.15); - next.chest.scale = Vec3::one(); - - next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_cos * 1.1); - next.belt.ori = Quaternion::rotation_z(wave * 0.25); - next.belt.scale = Vec3::one(); - - next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_cos * 1.1); - next.shorts.ori = Quaternion::rotation_z(wave * 0.4); - next.shorts.scale = Vec3::one(); match Tool::Hammer { //TODO: Inventory @@ -187,30 +167,6 @@ impl Animation for CrunAnimation { next.weapon.scale = Vec3::one(); } } - next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7); - next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5); - next.l_foot.scale = Vec3::one(); - - next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7); - next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5); - next.r_foot.scale = Vec3::one(); - - next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7); - next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15); - next.l_shoulder.scale = Vec3::one() * 1.1; - - next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7); - next.r_shoulder.ori = Quaternion::rotation_x(wave * 0.15); - next.r_shoulder.scale = Vec3::one() * 1.1; - - next.draw.offset = Vec3::new(0.0, 5.0, 0.0); - next.draw.ori = Quaternion::rotation_y(0.0); - next.draw.scale = Vec3::one() * 0.0; - - next.torso.offset = Vec3::new(0.0, -0.2 + wave * -0.08, 0.2) * skeleton_attr.scaler; - next.torso.ori = - Quaternion::rotation_x(wave_stop * velocity * -0.04 + wave_diff * velocity * -0.005); - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; next } diff --git a/voxygen/src/anim/character/mod.rs b/voxygen/src/anim/character/mod.rs index 138ca93a2b..c8ec0efbcf 100644 --- a/voxygen/src/anim/character/mod.rs +++ b/voxygen/src/anim/character/mod.rs @@ -1,25 +1,27 @@ pub mod attack; pub mod block; +pub mod blockidle; pub mod cidle; -pub mod cjump; -pub mod crun; pub mod gliding; pub mod idle; pub mod jump; pub mod roll; pub mod run; +pub mod stand; +pub mod wield; // Reexports pub use self::attack::AttackAnimation; pub use self::block::BlockAnimation; +pub use self::blockidle::BlockIdleAnimation; pub use self::cidle::CidleAnimation; -pub use self::cjump::CjumpAnimation; -pub use self::crun::CrunAnimation; pub use self::gliding::GlidingAnimation; pub use self::idle::IdleAnimation; pub use self::jump::JumpAnimation; pub use self::roll::RollAnimation; pub use self::run::RunAnimation; +pub use self::stand::StandAnimation; +pub use self::wield::WieldAnimation; use super::{Bone, Skeleton}; use crate::render::FigureBoneData; diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index be4d9c802a..759ae0c396 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -10,22 +10,22 @@ pub struct RunAnimation; impl Animation for RunAnimation { type Skeleton = CharacterSkeleton; - type Dependency = (f32, f64); + type Dependency = (f32, f32, f64); fn update_skeleton( skeleton: &Self::Skeleton, - (velocity, global_time): Self::Dependency, + (velocity, orientation, global_time): Self::Dependency, anim_time: f64, skeleton_attr: &SkeletonAttr, ) -> Self::Skeleton { let mut next = (*skeleton).clone(); - let wave = (anim_time as f32 * 12.0).sin(); - let wave_cos = (anim_time as f32 * 12.0).cos(); - let wave_diff = (anim_time as f32 * 12.0 + PI / 2.0).sin(); - let wave_cos_dub = (anim_time as f32 * 24.0).cos(); - let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin(); + let wave = (anim_time as f32 * velocity * 1.2).sin(); + let wave_cos = (anim_time as f32 * velocity * 1.2).cos(); + let wave_diff = (anim_time as f32 * velocity * 0.6).sin(); + let wave_cos_dub = (anim_time as f32 * velocity * 2.4).cos(); + let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin(); let head_look = Vec2::new( ((global_time + anim_time) as f32 / 2.0) .floor() @@ -39,6 +39,19 @@ impl Animation for RunAnimation { * 0.1, ); + let vel = Vec2::from(velocity); + let ori = (Vec2::from(orientation)).normalized(); + + let _tilt = if Vec2::new(ori, vel) + .map(|v| Vec2::::from(v).magnitude_squared()) + .reduce_partial_min() + > 0.001 + { + vel.normalized().dot(ori.normalized()).min(1.0).acos() + } else { + 0.0 + }; + next.head.offset = Vec3::new( 0.0, -1.0 + skeleton_attr.neck_forward, @@ -107,7 +120,8 @@ impl Animation for RunAnimation { next.torso.offset = Vec3::new(0.0, -0.2 + wave * -0.08, 0.4) * skeleton_attr.scaler; next.torso.ori = - Quaternion::rotation_x(wave_stop * velocity * -0.06 + wave_diff * velocity * -0.005); + Quaternion::rotation_x(wave_stop * velocity * -0.06 + wave_diff * velocity * -0.005) + * Quaternion::rotation_y(0.0); next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; next diff --git a/voxygen/src/anim/character/stand.rs b/voxygen/src/anim/character/stand.rs new file mode 100644 index 0000000000..c7057b1f1e --- /dev/null +++ b/voxygen/src/anim/character/stand.rs @@ -0,0 +1,112 @@ +use super::{ + super::{Animation, SkeletonAttr}, + CharacterSkeleton, +}; +use std::{f32::consts::PI, ops::Mul}; +use vek::*; + +pub struct Input { + pub attack: bool, +} +pub struct StandAnimation; + +impl Animation for StandAnimation { + type Skeleton = CharacterSkeleton; + type Dependency = f64; + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: f64, + anim_time: f64, + skeleton_attr: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + + let head_look = Vec2::new( + ((global_time + anim_time) as f32 / 12.0) + .floor() + .mul(7331.0) + .sin() + * 0.5, + ((global_time + anim_time) as f32 / 12.0) + .floor() + .mul(1337.0) + .sin() + * 0.25, + ); + next.head.offset = Vec3::new( + 0.0 + skeleton_attr.neck_right, + 0.0 + skeleton_attr.neck_forward, + skeleton_attr.neck_height + 15.0 + wave_ultra_slow * 0.3, + ); + next.head.ori = + Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y.abs()); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; + + next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_ultra_slow * 0.3); + next.chest.ori = Quaternion::rotation_x(0.0); + next.chest.scale = Vec3::one(); + + next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_ultra_slow * 0.3); + next.belt.ori = Quaternion::rotation_x(0.0); + next.belt.scale = Vec3::one(); + + next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_ultra_slow * 0.3); + next.shorts.ori = Quaternion::rotation_x(0.0); + next.shorts.scale = Vec3::one(); + + next.l_hand.offset = Vec3::new( + -7.5, + 0.0 + wave_ultra_slow_cos * 0.15, + 0.0 + wave_ultra_slow * 0.5, + ); + + next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06); + next.l_hand.scale = Vec3::one(); + + next.r_hand.offset = Vec3::new( + 7.5, + 0.0 + wave_ultra_slow_cos * 0.15, + 0.0 + wave_ultra_slow * 0.5, + ); + next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06); + next.r_hand.scale = Vec3::one(); + + next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0); + next.l_foot.ori = Quaternion::identity(); + next.l_foot.scale = Vec3::one(); + + next.r_foot.offset = Vec3::new(3.4, -0.1, 8.0); + next.r_foot.ori = Quaternion::identity(); + next.r_foot.scale = Vec3::one(); + + next.weapon.offset = Vec3::new( + -7.0 + skeleton_attr.weapon_x, + -5.0 + skeleton_attr.weapon_y, + 15.0, + ); + next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57); + next.weapon.scale = Vec3::one(); + + next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7); + next.l_shoulder.ori = Quaternion::rotation_x(0.0); + next.l_shoulder.scale = Vec3::one() * 1.1; + + next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7); + next.r_shoulder.ori = Quaternion::rotation_x(0.0); + next.r_shoulder.scale = Vec3::one() * 1.1; + + next.draw.offset = Vec3::new(0.0, 5.0, 0.0); + next.draw.ori = Quaternion::rotation_y(0.0); + next.draw.scale = Vec3::one() * 0.0; + + next.torso.offset = Vec3::new(0.0, -0.2, 0.1) * skeleton_attr.scaler; + next.torso.ori = Quaternion::rotation_x(0.0); + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + + next + } +} diff --git a/voxygen/src/anim/character/cjump.rs b/voxygen/src/anim/character/wield.rs similarity index 61% rename from voxygen/src/anim/character/cjump.rs rename to voxygen/src/anim/character/wield.rs index 6f4cf9720d..56bce3625e 100644 --- a/voxygen/src/anim/character/cjump.rs +++ b/voxygen/src/anim/character/wield.rs @@ -3,59 +3,37 @@ use super::{ CharacterSkeleton, }; use common::comp::item::Tool; -use std::f32::consts::PI; use vek::*; -pub struct CjumpAnimation; +pub struct WieldAnimation; -impl Animation for CjumpAnimation { +impl Animation for WieldAnimation { type Skeleton = CharacterSkeleton; - type Dependency = f64; + type Dependency = (f32, f64); fn update_skeleton( skeleton: &Self::Skeleton, - _global_time: f64, + (_velocity, _global_time): Self::Dependency, anim_time: f64, skeleton_attr: &SkeletonAttr, ) -> Self::Skeleton { let mut next = (*skeleton).clone(); - let wave_slow = (anim_time as f32 * 7.0).sin(); - let wave_stop = (anim_time as f32 * 4.5).min(PI / 2.0).sin(); - - next.head.offset = Vec3::new( - 0.0 + skeleton_attr.neck_right, - 0.0 + skeleton_attr.neck_forward, - skeleton_attr.neck_height + 15.0, - ); - next.head.ori = Quaternion::rotation_x(0.25 + wave_stop * 0.1 + wave_slow * 0.04); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; - - next.chest.offset = Vec3::new(0.0, 0.0, 8.0); - next.chest.ori = Quaternion::rotation_z(0.0); - next.chest.scale = Vec3::one(); - - next.belt.offset = Vec3::new(0.0, 0.0, 6.0); - next.belt.ori = Quaternion::rotation_z(0.0); - next.belt.scale = Vec3::one(); - - next.shorts.offset = Vec3::new(0.0, 0.0, 3.0); - next.shorts.ori = Quaternion::rotation_z(0.0); - next.shorts.scale = Vec3::one(); + let wave = (anim_time as f32 * 12.0).sin(); match Tool::Hammer { //TODO: Inventory Tool::Sword => { - next.l_hand.offset = Vec3::new(-7.0, 3.25, 0.25 + wave_stop * 2.0); + next.l_hand.offset = Vec3::new(-6.0, 3.75, 0.25); next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.scale = Vec3::one() * 1.01; - next.r_hand.offset = Vec3::new(-7.0, 3.0, -2.0 + wave_stop * 2.0); + next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0); next.r_hand.ori = Quaternion::rotation_x(-0.3); next.r_hand.scale = Vec3::one() * 1.01; next.weapon.offset = Vec3::new( - -7.0 + skeleton_attr.weapon_x, + -6.0 + skeleton_attr.weapon_x, 4.0 + skeleton_attr.weapon_y, - 0.0 + wave_stop * 2.0, + 0.0, ); next.weapon.ori = Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(0.0) @@ -80,45 +58,41 @@ impl Animation for CjumpAnimation { next.weapon.scale = Vec3::one(); } Tool::Hammer => { - next.l_hand.offset = Vec3::new(-7.0, 8.25, 2.0 + wave_stop * 2.0); + next.l_hand.offset = Vec3::new(-7.0, 8.25, 3.0); next.l_hand.ori = Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(-1.2) - * Quaternion::rotation_z(0.0); + * Quaternion::rotation_z(wave * -0.25); next.l_hand.scale = Vec3::one() * 1.01; - next.r_hand.offset = Vec3::new(7.0, 7.0, -3.0 + wave_stop * 2.0); + next.r_hand.offset = Vec3::new(7.0, 7.0, -1.5); next.r_hand.ori = Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(-1.2) - * Quaternion::rotation_z(0.0); + * Quaternion::rotation_z(wave * -0.25); next.r_hand.scale = Vec3::one() * 1.01; next.weapon.offset = Vec3::new( 5.0 + skeleton_attr.weapon_x, 8.75 + skeleton_attr.weapon_y, - -2.5 + wave_stop * 2.0, + -2.0, ); next.weapon.ori = Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(-1.2) - * Quaternion::rotation_z(0.0); + * Quaternion::rotation_z(wave * -0.25); next.weapon.scale = Vec3::one(); } Tool::Staff => { - next.l_hand.offset = Vec3::new(-7.0, 7.5, 0.0); - next.l_hand.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.7) - * Quaternion::rotation_z(1.0); + next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0); + next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.scale = Vec3::one() * 1.01; - next.r_hand.offset = Vec3::new(7.0, 6.25, 1.5); - next.r_hand.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.7) - * Quaternion::rotation_z(1.0); + next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0); + next.r_hand.ori = Quaternion::rotation_x(-0.3); next.r_hand.scale = Vec3::one() * 1.01; next.weapon.offset = Vec3::new( - 5.0 + skeleton_attr.weapon_x, - 8.0 + skeleton_attr.weapon_y, - 1.0, + -6.0 + skeleton_attr.weapon_x, + 4.5 + skeleton_attr.weapon_y, + 0.0, ); next.weapon.ori = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(-1.7) - * Quaternion::rotation_z(1.0); + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } Tool::SwordShield => { @@ -174,30 +148,6 @@ impl Animation for CjumpAnimation { } } - next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0); - next.l_foot.ori = Quaternion::rotation_x(wave_stop * -1.2 - wave_slow * 0.2); - next.l_foot.scale = Vec3::one(); - - next.r_foot.offset = Vec3::new(3.4, -1.0, 6.0); - next.r_foot.ori = Quaternion::rotation_x(wave_stop * 1.2 + wave_slow * 0.2); - next.r_foot.scale = Vec3::one(); - - next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7); - next.l_shoulder.ori = Quaternion::rotation_x(0.0); - next.l_shoulder.scale = Vec3::one() * 1.1; - - next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7); - next.r_shoulder.ori = Quaternion::rotation_x(0.0); - next.r_shoulder.scale = Vec3::one() * 1.1; - - next.draw.offset = Vec3::new(0.0, 5.0, 0.0); - next.draw.ori = Quaternion::rotation_y(0.0); - next.draw.scale = Vec3::one() * 0.0; - - next.torso.offset = Vec3::new(0.0, -0.2, 0.0) * skeleton_attr.scaler; - next.torso.ori = Quaternion::rotation_x(-0.2); - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; - next } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 4c457d93a6..3a868bf71b 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -1,7 +1,7 @@ use crate::{ anim::{ self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton, - quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr, + quadrupedmedium::QuadrupedMediumSkeleton, Animation as _, Skeleton, SkeletonAttr, }, mesh::Meshable, render::{ @@ -13,7 +13,8 @@ use client::Client; use common::{ assets, comp::{ - self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body, Equipment, Item, + humanoid, item::Tool, object, quadruped, quadruped_medium, ActionState::*, Body, + CharacterState, Equipment, Item, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel, }, figure::Segment, terrain::TerrainChunkSize, @@ -23,7 +24,7 @@ use dot_vox::DotVoxData; use hashbrown::HashMap; use log::debug; use specs::{Entity as EcsEntity, Join}; -use std::f32; +use std::{f32, time::Instant}; use vek::*; const DAMAGE_FADE_COEFFICIENT: f64 = 5.0; @@ -618,19 +619,20 @@ impl FigureMgr { let dt = client.state().get_delta_time(); // Get player position. let player_pos = ecs - .read_storage::() + .read_storage::() .get(client.entity()) .map_or(Vec3::zero(), |pos| pos.0); - for (entity, pos, vel, ori, scale, body, animation_info, stats) in ( + for (entity, pos, vel, ori, scale, body, character, last_character, stats) in ( &ecs.entities(), - &ecs.read_storage::(), - &ecs.read_storage::(), - &ecs.read_storage::(), - ecs.read_storage::().maybe(), - &ecs.read_storage::(), - ecs.read_storage::().maybe(), - ecs.read_storage::().maybe(), + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ecs.read_storage::().maybe(), + &ecs.read_storage::(), + ecs.read_storage::().maybe(), + ecs.read_storage::>().maybe(), + ecs.read_storage::().maybe(), ) .join() { @@ -683,80 +685,92 @@ impl FigureMgr { .character_states .entry(entity) .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); - - let animation_info = match animation_info { - Some(a_i) => a_i, - None => continue, + let (character, last_character) = match (character, last_character) { + (Some(c), Some(l)) => (c, l), + _ => continue, }; - let target_skeleton = match animation_info.animation { - comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton( - state.skeleton_mut(), + if !character.is_same_movement(&last_character.0) { + state.last_movement_change = Instant::now(); + } + if !character.is_same_action(&last_character.0) { + state.last_action_change = Instant::now(); + } + + let time_since_movement_change = + state.last_movement_change.elapsed().as_secs_f64(); + let time_since_action_change = state.last_action_change.elapsed().as_secs_f64(); + + let target_base = match &character.movement { + Stand => anim::character::StandAnimation::update_skeleton( + &CharacterSkeleton::new(), time, - animation_info.time, + time_since_movement_change, skeleton_attr, ), - comp::Animation::Run => anim::character::RunAnimation::update_skeleton( - state.skeleton_mut(), + Run => anim::character::RunAnimation::update_skeleton( + &CharacterSkeleton::new(), + (vel.0.magnitude(), ori.0.magnitude(), time), + time_since_movement_change, + skeleton_attr, + ), + Jump => anim::character::JumpAnimation::update_skeleton( + &CharacterSkeleton::new(), + time, + time_since_movement_change, + skeleton_attr, + ), + Roll { .. } => anim::character::RollAnimation::update_skeleton( + &CharacterSkeleton::new(), + time, + time_since_movement_change, + skeleton_attr, + ), + Glide => anim::character::GlidingAnimation::update_skeleton( + &CharacterSkeleton::new(), (vel.0.magnitude(), time), - animation_info.time, + time_since_movement_change, skeleton_attr, ), - comp::Animation::Jump => anim::character::JumpAnimation::update_skeleton( - state.skeleton_mut(), + }; + + let target_bones = match (&character.movement, &character.action) { + (Stand, Wield { .. }) => anim::character::CidleAnimation::update_skeleton( + &target_base, time, - animation_info.time, + time_since_action_change, skeleton_attr, ), - comp::Animation::Attack => { - anim::character::AttackAnimation::update_skeleton( - state.skeleton_mut(), + (Stand, Block { .. }) => { + anim::character::BlockIdleAnimation::update_skeleton( + &target_base, time, - animation_info.time, + time_since_action_change, skeleton_attr, ) } - comp::Animation::Block => anim::character::BlockAnimation::update_skeleton( - state.skeleton_mut(), + (_, Attack { .. }) => anim::character::AttackAnimation::update_skeleton( + &target_base, time, - animation_info.time, + time_since_action_change, skeleton_attr, ), - comp::Animation::Cjump => anim::character::CjumpAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_info.time, - skeleton_attr, - ), - comp::Animation::Roll => anim::character::RollAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_info.time, - skeleton_attr, - ), - comp::Animation::Crun => anim::character::CrunAnimation::update_skeleton( - state.skeleton_mut(), + (_, Wield { .. }) => anim::character::WieldAnimation::update_skeleton( + &target_base, (vel.0.magnitude(), time), - animation_info.time, + time_since_action_change, skeleton_attr, ), - comp::Animation::Cidle => anim::character::CidleAnimation::update_skeleton( - state.skeleton_mut(), + (_, Block { .. }) => anim::character::BlockAnimation::update_skeleton( + &target_base, time, - animation_info.time, + time_since_action_change, skeleton_attr, ), - comp::Animation::Gliding => { - anim::character::GlidingAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_info.time, - skeleton_attr, - ) - } + _ => target_base, }; + state.skeleton.interpolate(&target_bones, dt); - state.skeleton.interpolate(&target_skeleton, dt); state.update(renderer, pos.0, ori.0, scale, col, dt); } Body::Quadruped(_) => { @@ -765,42 +779,43 @@ impl FigureMgr { .entry(entity) .or_insert_with(|| FigureState::new(renderer, QuadrupedSkeleton::new())); - let animation_info = match animation_info { - Some(a_i) => a_i, - None => continue, + let (character, last_character) = match (character, last_character) { + (Some(c), Some(l)) => (c, l), + _ => continue, }; - let target_skeleton = match animation_info.animation { - comp::Animation::Run | comp::Animation::Crun => { - anim::quadruped::RunAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_info.time, - skeleton_attr, - ) - } - comp::Animation::Idle | comp::Animation::Cidle => { - anim::quadruped::IdleAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_info.time, - skeleton_attr, - ) - } - comp::Animation::Jump | comp::Animation::Cjump => { - anim::quadruped::JumpAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_info.time, - skeleton_attr, - ) - } + if !character.is_same_movement(&last_character.0) { + state.last_movement_change = Instant::now(); + } + + let time_since_movement_change = + state.last_movement_change.elapsed().as_secs_f64(); + + let target_base = match character.movement { + Stand => anim::quadruped::IdleAnimation::update_skeleton( + &QuadrupedSkeleton::new(), + time, + time_since_movement_change, + skeleton_attr, + ), + Run => anim::quadruped::RunAnimation::update_skeleton( + &QuadrupedSkeleton::new(), + (vel.0.magnitude(), time), + time_since_movement_change, + skeleton_attr, + ), + Jump => anim::quadruped::JumpAnimation::update_skeleton( + &QuadrupedSkeleton::new(), + (vel.0.magnitude(), time), + time_since_movement_change, + skeleton_attr, + ), // TODO! _ => state.skeleton_mut().clone(), }; - state.skeleton.interpolate(&target_skeleton, dt); + state.skeleton.interpolate(&target_base, dt); state.update(renderer, pos.0, ori.0, scale, col, dt); } Body::QuadrupedMedium(_) => { @@ -811,42 +826,43 @@ impl FigureMgr { FigureState::new(renderer, QuadrupedMediumSkeleton::new()) }); - let animation_info = match animation_info { - Some(a_i) => a_i, - None => continue, + let (character, last_character) = match (character, last_character) { + (Some(c), Some(l)) => (c, l), + _ => continue, }; - let target_skeleton = match animation_info.animation { - comp::Animation::Run | comp::Animation::Crun => { - anim::quadrupedmedium::RunAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_info.time, - skeleton_attr, - ) - } - comp::Animation::Idle | comp::Animation::Cidle => { - anim::quadrupedmedium::IdleAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_info.time, - skeleton_attr, - ) - } - comp::Animation::Jump | comp::Animation::Cjump => { - anim::quadrupedmedium::JumpAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_info.time, - skeleton_attr, - ) - } + if !character.is_same_movement(&last_character.0) { + state.last_movement_change = Instant::now(); + } + + let time_since_movement_change = + state.last_movement_change.elapsed().as_secs_f64(); + + let target_base = match character.movement { + Stand => anim::quadrupedmedium::IdleAnimation::update_skeleton( + &QuadrupedMediumSkeleton::new(), + time, + time_since_movement_change, + skeleton_attr, + ), + Run => anim::quadrupedmedium::RunAnimation::update_skeleton( + &QuadrupedMediumSkeleton::new(), + (vel.0.magnitude(), time), + time_since_movement_change, + skeleton_attr, + ), + Jump => anim::quadrupedmedium::JumpAnimation::update_skeleton( + &QuadrupedMediumSkeleton::new(), + (vel.0.magnitude(), time), + time_since_movement_change, + skeleton_attr, + ), // TODO! _ => state.skeleton_mut().clone(), }; - state.skeleton.interpolate(&target_skeleton, dt); + state.skeleton.interpolate(&target_base, dt); state.update(renderer, pos.0, ori.0, scale, col, dt); } Body::Object(_) => { @@ -887,12 +903,12 @@ impl FigureMgr { for (entity, _, _, _, body, stats, _) in ( &ecs.entities(), - &ecs.read_storage::(), - &ecs.read_storage::(), - &ecs.read_storage::(), - &ecs.read_storage::(), - ecs.read_storage::().maybe(), - ecs.read_storage::().maybe(), + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), ) .join() // Don't render figures outside of frustum (camera viewport, max draw distance is farplane) @@ -901,7 +917,7 @@ impl FigureMgr { &pos.0.x, &pos.0.y, &pos.0.z, - &(scale.unwrap_or(&comp::Scale(1.0)).0 * 2.0), + &(scale.unwrap_or(&Scale(1.0)).0 * 2.0), ) }) // Don't render dead entities @@ -934,7 +950,7 @@ impl FigureMgr { if camera.get_mode() == CameraMode::FirstPerson && client .state() - .read_storage::() + .read_storage::() .get(client.entity()) .is_some() && entity == client.entity() @@ -953,6 +969,8 @@ impl FigureMgr { pub struct FigureState { bone_consts: Consts, locals: Consts, + last_movement_change: Instant, + last_action_change: Instant, skeleton: S, pos: Vec3, ori: Vec3, @@ -965,6 +983,8 @@ impl FigureState { .create_consts(&skeleton.compute_matrices()) .unwrap(), locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(), + last_movement_change: Instant::now(), + last_action_change: Instant::now(), skeleton, pos: Vec3::zero(), ori: Vec3::zero(),