From 043016a4330a670e40292e7e42f29dccd8ccc2f6 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 16 Jan 2022 17:06:35 +0000 Subject: [PATCH] Don't try to mount unmountable entities, clippy fixes and fmt --- client/src/lib.rs | 4 +- common/net/src/msg/ecs_packet.rs | 8 +- common/src/comp/agent.rs | 4 +- common/src/comp/mod.rs | 3 +- common/src/lib.rs | 7 +- common/src/link.rs | 34 ++++--- common/src/mounting.rs | 114 ++++++++++++++--------- common/src/terrain/mod.rs | 8 +- common/state/src/state.rs | 9 +- common/systems/src/character_behavior.rs | 4 +- common/systems/src/mount.rs | 18 +--- common/systems/src/phys.rs | 20 ++-- server/src/cmd.rs | 28 ++++-- server/src/events/interaction.rs | 33 +++---- server/src/rtsim/entity.rs | 10 +- server/src/state_ext.rs | 32 +++---- server/src/sys/agent.rs | 32 +++---- server/src/sys/entity_sync.rs | 4 +- server/src/sys/sentinel.rs | 10 +- voxygen/src/hud/mod.rs | 91 +++++++++++------- voxygen/src/hud/overhead.rs | 63 ++++++++----- voxygen/src/hud/overitem.rs | 39 +++++--- voxygen/src/scene/figure/mod.rs | 19 +++- voxygen/src/session/mod.rs | 10 +- 24 files changed, 351 insertions(+), 253 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 2d848d5fba..faa68a93ba 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -34,6 +34,8 @@ use common::{ }, event::{EventBus, LocalEvent}, grid::Grid, + link::Is, + mounting::Rider, outcome::Outcome, recipe::RecipeBook, resources::{PlayerEntity, TimeOfDay}, @@ -44,8 +46,6 @@ use common::{ trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult}, uid::{Uid, UidAllocator}, vol::RectVolSize, - mounting::Rider, - link::Is, }; use common_base::{prof_span, span}; use common_net::{ diff --git a/common/net/src/msg/ecs_packet.rs b/common/net/src/msg/ecs_packet.rs index 75bad6cc22..83a4007250 100644 --- a/common/net/src/msg/ecs_packet.rs +++ b/common/net/src/msg/ecs_packet.rs @@ -1,9 +1,9 @@ use crate::sync; use common::{ comp, - resources::Time, - mounting::{Mount, Rider}, link::Is, + mounting::{Mount, Rider}, + resources::Time, }; use serde::{Deserialize, Serialize}; use specs::WorldExt; @@ -215,7 +215,9 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPhantom::Vel(_) => sync::handle_interp_remove::(entity, world), EcsCompPhantom::Ori(_) => sync::handle_interp_remove::(entity, world), EcsCompPhantom::Shockwave(_) => sync::handle_remove::(entity, world), - EcsCompPhantom::BeamSegment(_) => sync::handle_remove::(entity, world), + EcsCompPhantom::BeamSegment(_) => { + sync::handle_remove::(entity, world) + }, EcsCompPhantom::Alignment(_) => sync::handle_remove::(entity, world), } } diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index b31d672669..484d0261b7 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -8,8 +8,8 @@ use crate::{ trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult}, uid::Uid, }; -use serde::{Serialize, Deserialize}; -use specs::{Component, Entity as EcsEntity, DerefFlaggedStorage}; +use serde::{Deserialize, Serialize}; +use specs::{Component, DerefFlaggedStorage, Entity as EcsEntity}; use specs_idvs::IdvStorage; use std::{collections::VecDeque, fmt}; use strum::IntoEnumIterator; diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 18a8ac22dc..a75ebfb387 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -73,8 +73,7 @@ pub use self::{ combo::Combo, controller::{ Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputAttr, - InputKind, InventoryAction, InventoryEvent, InventoryManip, - UtteranceKind, + InputKind, InventoryAction, InventoryEvent, InventoryManip, UtteranceKind, }, energy::Energy, fluid_dynamics::Fluid, diff --git a/common/src/lib.rs b/common/src/lib.rs index 686385d78a..ac0470bff2 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -48,8 +48,11 @@ pub mod figure; #[cfg(not(target_arch = "wasm32"))] pub mod generation; #[cfg(not(target_arch = "wasm32"))] pub mod grid; +#[cfg(not(target_arch = "wasm32"))] pub mod link; #[cfg(not(target_arch = "wasm32"))] pub mod lottery; +#[cfg(not(target_arch = "wasm32"))] +pub mod mounting; #[cfg(not(target_arch = "wasm32"))] pub mod npc; #[cfg(not(target_arch = "wasm32"))] pub mod outcome; @@ -80,10 +83,6 @@ pub mod uid; #[cfg(not(target_arch = "wasm32"))] pub mod vol; #[cfg(not(target_arch = "wasm32"))] pub mod volumes; -#[cfg(not(target_arch = "wasm32"))] -pub mod link; -#[cfg(not(target_arch = "wasm32"))] -pub mod mounting; #[cfg(not(target_arch = "wasm32"))] pub use cached_spatial_grid::CachedSpatialGrid; diff --git a/common/src/link.rs b/common/src/link.rs index 7245e168f9..9cdee123c0 100644 --- a/common/src/link.rs +++ b/common/src/link.rs @@ -1,14 +1,13 @@ use serde::{Deserialize, Serialize}; -use specs::{SystemData, Component, DerefFlaggedStorage}; +use specs::{Component, DerefFlaggedStorage, SystemData}; use specs_idvs::IdvStorage; -use std::{ - ops::Deref, - sync::Arc, -}; +use std::{ops::Deref, sync::Arc}; pub trait Link: Sized + Send + Sync + 'static { + type Error; + type CreateData<'a>: SystemData<'a>; - fn create(this: &LinkHandle, data: Self::CreateData<'_>) -> Result<(), ()>; + fn create(this: &LinkHandle, data: Self::CreateData<'_>) -> Result<(), Self::Error>; type PersistData<'a>: SystemData<'a>; fn persist(this: &LinkHandle, data: Self::PersistData<'_>) -> bool; @@ -35,16 +34,22 @@ impl Is { } impl Clone for Is { - fn clone(&self) -> Self { Self { link: self.link.clone() } } + fn clone(&self) -> Self { + Self { + link: self.link.clone(), + } + } } impl Deref for Is { type Target = R::Link; + fn deref(&self) -> &Self::Target { &self.link } } impl Component for Is - where R::Link: Send + Sync + 'static +where + R::Link: Send + Sync + 'static, { type Storage = DerefFlaggedStorage>; } @@ -56,21 +61,24 @@ pub struct LinkHandle { impl Clone for LinkHandle { fn clone(&self) -> Self { - Self { link: self.link.clone() } + Self { + link: Arc::clone(&self.link), + } } } impl LinkHandle { pub fn from_link(link: L) -> Self { - Self { link: Arc::new(link) } + Self { + link: Arc::new(link), + } } - pub fn make_role>(&self) -> Is { - Is { link: self.clone() } - } + pub fn make_role>(&self) -> Is { Is { link: self.clone() } } } impl Deref for LinkHandle { type Target = L; + fn deref(&self) -> &Self::Target { &self.link } } diff --git a/common/src/mounting.rs b/common/src/mounting.rs index bc6c08ce4c..bfc0c6b185 100644 --- a/common/src/mounting.rs +++ b/common/src/mounting.rs @@ -1,12 +1,11 @@ use crate::{ comp, - link::{Is, Link, Role, LinkHandle}, - uid::{Uid, UidAllocator}, + link::{Is, Link, LinkHandle, Role}, terrain::TerrainGrid, + uid::{Uid, UidAllocator}, }; -use specs::{Entities, ReadStorage, Read, ReadExpect, WriteStorage}; -use specs::saveload::MarkerAllocator; use serde::{Deserialize, Serialize}; +use specs::{saveload::MarkerAllocator, Entities, Read, ReadExpect, ReadStorage, WriteStorage}; use vek::*; #[derive(Serialize, Deserialize, Debug)] @@ -29,35 +28,26 @@ pub struct Mounting { pub rider: Uid, } +pub enum MountingError { + NoSuchEntity, + NotMountable, +} + impl Link for Mounting { type CreateData<'a> = ( Read<'a, UidAllocator>, WriteStorage<'a, Is>, WriteStorage<'a, Is>, ); - fn create(this: &LinkHandle, (uid_allocator, mut is_mounts, mut is_riders): Self::CreateData<'_>) -> Result<(), ()> { - let entity = |uid: Uid| uid_allocator - .retrieve_entity_internal(uid.into()); - - if this.mount == this.rider { - // Forbid self-mounting - Err(()) - } else if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) { - let can_mount_with = |entity| is_mounts.get(entity).is_none() && is_riders.get(entity).is_none(); - - // Ensure that neither mount or rider are already part of a mounting relationship - if can_mount_with(mount) && can_mount_with(rider) { - let _ = is_mounts.insert(mount, this.make_role()); - let _ = is_riders.insert(rider, this.make_role()); - Ok(()) - } else { - Err(()) - } - } else { - Err(()) - } - } - + type DeleteData<'a> = ( + Read<'a, UidAllocator>, + WriteStorage<'a, Is>, + WriteStorage<'a, Is>, + WriteStorage<'a, comp::Pos>, + WriteStorage<'a, comp::ForceUpdate>, + ReadExpect<'a, TerrainGrid>, + ); + type Error = MountingError; type PersistData<'a> = ( Read<'a, UidAllocator>, Entities<'a>, @@ -65,12 +55,44 @@ impl Link for Mounting { ReadStorage<'a, Is>, ReadStorage<'a, Is>, ); - fn persist(this: &LinkHandle, (uid_allocator, entities, healths, is_mounts, is_riders): Self::PersistData<'_>) -> bool { - let entity = |uid: Uid| uid_allocator - .retrieve_entity_internal(uid.into()); + + fn create( + this: &LinkHandle, + (uid_allocator, mut is_mounts, mut is_riders): Self::CreateData<'_>, + ) -> Result<(), Self::Error> { + let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); + + if this.mount == this.rider { + // Forbid self-mounting + Err(MountingError::NotMountable) + } else if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) { + let can_mount_with = + |entity| is_mounts.get(entity).is_none() && is_riders.get(entity).is_none(); + + // Ensure that neither mount or rider are already part of a mounting + // relationship + if can_mount_with(mount) && can_mount_with(rider) { + let _ = is_mounts.insert(mount, this.make_role()); + let _ = is_riders.insert(rider, this.make_role()); + Ok(()) + } else { + Err(MountingError::NotMountable) + } + } else { + Err(MountingError::NoSuchEntity) + } + } + + fn persist( + this: &LinkHandle, + (uid_allocator, entities, healths, is_mounts, is_riders): Self::PersistData<'_>, + ) -> bool { + let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); if let Some((mount, rider)) = entity(this.mount).zip(entity(this.rider)) { - let is_alive = |entity| entities.is_alive(entity) && healths.get(entity).map_or(true, |h| !h.is_dead); + let is_alive = |entity| { + entities.is_alive(entity) && healths.get(entity).map_or(true, |h| !h.is_dead) + }; // Ensure that both entities are alive and that they continue to be linked is_alive(mount) @@ -82,17 +104,11 @@ impl Link for Mounting { } } - type DeleteData<'a> = ( - Read<'a, UidAllocator>, - WriteStorage<'a, Is>, - WriteStorage<'a, Is>, - WriteStorage<'a, comp::Pos>, - WriteStorage<'a, comp::ForceUpdate>, - ReadExpect<'a, TerrainGrid>, - ); - fn delete(this: &LinkHandle, (uid_allocator, mut is_mounts, mut is_riders, mut positions, mut force_update, terrain): Self::DeleteData<'_>) { - let entity = |uid: Uid| uid_allocator - .retrieve_entity_internal(uid.into()); + fn delete( + this: &LinkHandle, + (uid_allocator, mut is_mounts, mut is_riders, mut positions, mut force_update, terrain): Self::DeleteData<'_>, + ) { + let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let mount = entity(this.mount); let rider = entity(this.rider); @@ -105,9 +121,15 @@ impl Link for Mounting { let safe_pos = rider .and_then(|rider| positions.get(rider).copied()) .filter(|rider_pos| terrain.is_space(rider_pos.0.map(|e| e.floor() as i32))) - .or_else(|| mount - .and_then(|mount| positions.get(mount).copied()) - .filter(|mount_pos| terrain.is_space((mount_pos.0 + Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)))); + .or_else(|| { + mount + .and_then(|mount| positions.get(mount).copied()) + .filter(|mount_pos| { + terrain.is_space( + (mount_pos.0 + Vec3::unit_z() * 0.1).map(|e| e.floor() as i32), + ) + }) + }); rider .and_then(|rider| Some(rider).zip(positions.get_mut(rider))) .map(|(rider, pos)| { @@ -115,7 +137,7 @@ impl Link for Mounting { pos.0 = safe_pos .map(|p| p.0.map(|e| e.floor())) .unwrap_or_else(|| terrain.find_space(old_pos).map(|e| e as f32)) - + Vec3::new(0.5, 0.5, 0.0); + + Vec3::new(0.5, 0.5, 0.0); let _ = force_update.insert(rider, comp::ForceUpdate); }); } diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index d7812d4065..ecaf113f74 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -174,9 +174,11 @@ impl TerrainGrid { (0..SEARCH_DIST * 2 + 1) .map(|i| if i % 2 == 0 { i } else { -i } / 2) .map(|z_diff| pos + Vec3::unit_z() * z_diff) - .find(|pos| self.get(pos - Vec3::unit_z()) - .map_or(false, |b| b.is_filled()) - && self.is_space(*pos)) + .find(|pos| { + self.get(pos - Vec3::unit_z()) + .map_or(false, |b| b.is_filled()) + && self.is_space(*pos) + }) } } diff --git a/common/state/src/state.rs b/common/state/src/state.rs index 4cc615c525..09bc81f754 100644 --- a/common/state/src/state.rs +++ b/common/state/src/state.rs @@ -8,6 +8,8 @@ use common::{ calendar::Calendar, comp, event::{EventBus, LocalEvent, ServerEvent}, + link::Is, + mounting::{Mount, Rider}, outcome::Outcome, region::RegionMap, resources::{ @@ -19,8 +21,6 @@ use common::{ time::DayPeriod, trade::Trades, vol::{ReadVol, WriteVol}, - link::Is, - mounting::{Mount, Rider}, }; use common_base::span; use common_ecs::{PhysicsMetrics, SysMetrics}; @@ -34,10 +34,7 @@ use specs::{ storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage}, Component, DispatcherBuilder, Entity as EcsEntity, WorldExt, }; -use std::{ - ops::{Deref, DerefMut}, - sync::Arc, -}; +use std::sync::Arc; use vek::*; /// How much faster should an in-game day be compared to a real day? diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index 4c506a9b52..26838fe3e5 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -11,6 +11,8 @@ use common::{ StateUpdate, Stats, Vel, }, event::{EventBus, LocalEvent, ServerEvent}, + link::Is, + mounting::Rider, outcome::Outcome, resources::{DeltaTime, Time}, states::{ @@ -19,8 +21,6 @@ use common::{ }, terrain::TerrainGrid, uid::Uid, - mounting::Rider, - link::Is, }; use common_ecs::{Job, Origin, Phase, System}; diff --git a/common/systems/src/mount.rs b/common/systems/src/mount.rs index d098ba51e4..ff88356beb 100644 --- a/common/systems/src/mount.rs +++ b/common/systems/src/mount.rs @@ -1,14 +1,13 @@ use common::{ - comp::{Body, Controller, Ori, Pos, Vel, ForceUpdate}, - uid::UidAllocator, - mounting::{Mount, Rider}, + comp::{Body, Controller, Ori, Pos, Vel}, link::Is, - uid::Uid, + mounting::Mount, + uid::UidAllocator, }; use common_ecs::{Job, Origin, Phase, System}; use specs::{ saveload::{Marker, MarkerAllocator}, - Entities, Join, Read, ReadStorage, WriteStorage, WriteExpect, + Entities, Join, Read, ReadStorage, WriteStorage, }; use vek::*; @@ -20,14 +19,11 @@ impl<'a> System<'a> for Sys { type SystemData = ( Read<'a, UidAllocator>, Entities<'a>, - ReadStorage<'a, Uid>, WriteStorage<'a, Controller>, - ReadStorage<'a, Is>, ReadStorage<'a, Is>, WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, - ReadStorage<'a, ForceUpdate>, ReadStorage<'a, Body>, ); @@ -40,14 +36,11 @@ impl<'a> System<'a> for Sys { ( uid_allocator, entities, - uids, mut controllers, - is_riders, is_mounts, mut positions, mut velocities, mut orientations, - force_updates, bodies, ): Self::SystemData, ) { @@ -71,8 +64,7 @@ impl<'a> System<'a> for Sys { let mounter_body = bodies.get(rider); let mounting_offset = body.map_or(Vec3::unit_z(), Body::mount_offset) + mounter_body.map_or(Vec3::zero(), Body::rider_offset); - let _ = positions - .insert(rider, Pos(pos.0 + ori.to_quat() * mounting_offset)); + let _ = positions.insert(rider, Pos(pos.0 + ori.to_quat() * mounting_offset)); let _ = orientations.insert(rider, ori); let _ = velocities.insert(rider, vel); } diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index 219f8d82df..7a47c1400e 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -2,11 +2,13 @@ use common::{ comp::{ body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST}, fluid_dynamics::{Fluid, LiquidKind, Wings}, - Body, CharacterState, Collider, Density, Mass, Ori, PhysicsState, Pos, - PosVelOriDefer, PreviousPhysCache, Projectile, Scale, Stats, Sticky, Vel, + Body, CharacterState, Collider, Density, Mass, Ori, PhysicsState, Pos, PosVelOriDefer, + PreviousPhysCache, Projectile, Scale, Stats, Sticky, Vel, }, consts::{AIR_DENSITY, FRIC_GROUND, GRAVITY}, event::{EventBus, ServerEvent}, + link::Is, + mounting::Rider, outcome::Outcome, resources::DeltaTime, states, @@ -14,8 +16,6 @@ use common::{ uid::Uid, util::{Projection, SpatialGrid}, vol::{BaseVol, ReadVol}, - mounting::Rider, - link::Is, }; use common_base::{prof_span, span}; use common_ecs::{Job, Origin, ParMode, Phase, PhysicsMetrics, System}; @@ -1851,7 +1851,8 @@ fn resolve_e2e_collision( // // This allows using e2e pushback to gain speed by jumping out of a roll // while in the middle of a collider, this is an intentional combat mechanic. - let forced_movement = matches!(char_state_maybe, Some(cs) if cs.is_forced_movement()) || is_riding; + let forced_movement = + matches!(char_state_maybe, Some(cs) if cs.is_forced_movement()) || is_riding; // Don't apply repulsive force to projectiles, // or if we're colliding with a terrain-like entity, @@ -1873,7 +1874,14 @@ fn resolve_e2e_collision( let diff = diff.normalized(); - *vel_delta += Vec3::from(diff) * force * step_delta * vel.0.xy().try_normalized().map_or(1.0, |dir| diff.dot(-dir).max(0.025)); + *vel_delta += Vec3::from(diff) + * force + * step_delta + * vel + .0 + .xy() + .try_normalized() + .map_or(1.0, |dir| diff.dot(-dir).max(0.025)); } *collision_registered = true; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 5df26620af..c9a4787b08 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -34,14 +34,14 @@ use common::{ effect::Effect, event::{EventBus, ServerEvent}, generation::{EntityConfig, EntityInfo}, + link::Is, + mounting::Rider, npc::{self, get_npc_name}, resources::{BattleMode, PlayerPhysicsSettings, Time, TimeOfDay}, terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize}, uid::{Uid, UidAllocator}, vol::{ReadVol, RectVolSize}, Damage, DamageKind, DamageSource, Explosion, LoadoutBuilder, RadiusEffect, - link::Is, - mounting::Rider, }; use common_net::{ msg::{DisconnectReason, Notification, PlayerListUpdate, ServerGeneral}, @@ -52,7 +52,9 @@ use core::{cmp::Ordering, convert::TryFrom, time::Duration}; use hashbrown::{HashMap, HashSet}; use humantime::Duration as HumanDuration; use rand::Rng; -use specs::{storage::StorageEntry, Builder, Entity as EcsEntity, Join, WorldExt, saveload::MarkerAllocator}; +use specs::{ + saveload::MarkerAllocator, storage::StorageEntry, Builder, Entity as EcsEntity, Join, WorldExt, +}; use std::{str::FromStr, sync::Arc}; use vek::*; use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement}; @@ -203,24 +205,30 @@ fn position_mut( descriptor: &str, f: impl for<'a> FnOnce(&'a mut comp::Pos) -> T, ) -> CmdResult { - let entity = server.state + let entity = server + .state .ecs() .read_storage::>() .get(entity) - .and_then(|is_rider| server.state - .ecs() - .read_resource::() - .retrieve_entity_internal(is_rider.mount.into())) + .and_then(|is_rider| { + server + .state + .ecs() + .read_resource::() + .retrieve_entity_internal(is_rider.mount.into()) + }) .unwrap_or(entity); - let res = server.state + let res = server + .state .ecs() .write_storage::() .get_mut(entity) .map(f) .ok_or_else(|| format!("Cannot get position for {:?}!", descriptor)); if res.is_ok() { - let _ = server.state + let _ = server + .state .ecs() .write_storage::() .insert(entity, comp::ForceUpdate); diff --git a/server/src/events/interaction.rs b/server/src/events/interaction.rs index 8996d4a591..2a9a6325bf 100644 --- a/server/src/events/interaction.rs +++ b/server/src/events/interaction.rs @@ -15,12 +15,12 @@ use common::{ Inventory, Pos, SkillGroupKind, }, consts::{MAX_MOUNT_RANGE, SOUND_TRAVEL_DIST_PER_VOLUME}, + link::Is, + mounting::{Mount, Mounting, Rider}, outcome::Outcome, terrain::{Block, SpriteKind}, uid::Uid, vol::ReadVol, - mounting::{Mount, Rider, Mounting}, - link::Is, }; use common_net::{msg::ServerGeneral, sync::WorldSyncExt}; @@ -102,17 +102,8 @@ pub fn handle_npc_interaction(server: &mut Server, interactor: EcsEntity, npc_en pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) { let state = server.state_mut(); - if state - .ecs() - .read_storage::>() - .get(rider) - .is_none() - { - let not_mounting_yet = state - .ecs() - .read_storage::>() - .get(mount) - .is_none(); + if state.ecs().read_storage::>().get(rider).is_none() { + let not_mounting_yet = state.ecs().read_storage::>().get(mount).is_none(); let within_range = || { let positions = state.ecs().read_storage::(); @@ -126,10 +117,13 @@ pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) { if let (Some(rider_uid), Some(mount_uid)) = (uids.get(rider).copied(), uids.get(mount).copied()) { - let is_pet = match state.ecs().read_storage::().get(mount) { - Some(comp::Alignment::Owned(owner)) if *owner == rider_uid => true, - _ => false, - }; + let is_pet = matches!( + state + .ecs() + .read_storage::() + .get(mount), + Some(comp::Alignment::Owned(owner)) if *owner == rider_uid, + ); if is_pet { drop(uids); @@ -146,10 +140,7 @@ pub fn handle_mount(server: &mut Server, rider: EcsEntity, mount: EcsEntity) { pub fn handle_unmount(server: &mut Server, rider: EcsEntity) { let state = server.state_mut(); - state - .ecs() - .write_storage::>() - .remove(rider); + state.ecs().write_storage::>().remove(rider); } /// FIXME: This code is dangerous and needs to be refactored. We can't just diff --git a/server/src/rtsim/entity.rs b/server/src/rtsim/entity.rs index a617991f20..72e8c028fe 100644 --- a/server/src/rtsim/entity.rs +++ b/server/src/rtsim/entity.rs @@ -1,6 +1,9 @@ use super::*; use common::{ - comp::inventory::{loadout_builder::{make_potion_bag, make_food_bag}, slot::ArmorSlot}, + comp::inventory::{ + loadout_builder::{make_food_bag, make_potion_bag}, + slot::ArmorSlot, + }, resources::Time, rtsim::{Memory, MemoryItem}, store::Id, @@ -142,9 +145,8 @@ impl Entity { // give potions to traveler humanoids or return loadout as is otherwise match (body, kind) { - (comp::Body::Humanoid(_), RtSimEntityKind::Random) => { - |l, _| l - .bag(ArmorSlot::Bag1, Some(make_potion_bag(100))) + (comp::Body::Humanoid(_), RtSimEntityKind::Random) => |l, _| { + l.bag(ArmorSlot::Bag1, Some(make_potion_bag(100))) .bag(ArmorSlot::Bag2, Some(make_food_bag(100))) }, (_, RtSimEntityKind::Merchant) => { diff --git a/server/src/state_ext.rs b/server/src/state_ext.rs index b3a49e4e4e..7c32742f1b 100644 --- a/server/src/state_ext.rs +++ b/server/src/state_ext.rs @@ -18,11 +18,11 @@ use common::{ Group, Inventory, Poise, }, effect::Effect, + link::{Link, LinkHandle}, + mounting::Mounting, resources::{Time, TimeOfDay}, slowjob::SlowJobPool, uid::{Uid, UidAllocator}, - link::{Is, Link, Role, LinkHandle}, - mounting::Mounting, }; use common_net::{ msg::{CharacterInfo, PlayerListUpdate, PresenceKind, ServerGeneral}, @@ -32,7 +32,7 @@ use common_state::State; use rand::prelude::*; use specs::{ saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, - Join, WorldExt, Component, + Join, WorldExt, }; use std::time::Duration; use tracing::{trace, warn}; @@ -112,8 +112,9 @@ pub trait StateExt { fn send_chat(&self, msg: comp::UnresolvedChatMsg); fn notify_players(&self, msg: ServerGeneral); fn notify_in_game_clients(&self, msg: ServerGeneral); - /// Create a new link between entities (see [`common::mounting`] for an example). - fn link(&mut self, link: L) -> Result<(), ()>; + /// Create a new link between entities (see [`common::mounting`] for an + /// example). + fn link(&mut self, link: L) -> Result<(), L::Error>; /// Maintain active links between entities fn maintain_links(&mut self); /// Delete an entity, recording the deletion in [`DeletedEntities`] @@ -277,7 +278,7 @@ impl StateExt for State { mountable: bool, ) -> EcsEntityBuilder { let body = comp::Body::Ship(ship); - let mut builder = self + let builder = self .ecs_mut() .create_entity_synced() .with(pos) @@ -831,13 +832,10 @@ impl StateExt for State { } } - fn link(&mut self, link: L) -> Result<(), ()> { + fn link(&mut self, link: L) -> Result<(), L::Error> { let linker = LinkHandle::from_link(link); - L::create( - &linker, - self.ecs().system_data(), - )?; + L::create(&linker, self.ecs().system_data())?; self.ecs_mut() .entry::>>() @@ -850,11 +848,13 @@ impl StateExt for State { fn maintain_links(&mut self) { fn maintain_link(state: &State) { if let Some(mut handles) = state.ecs().try_fetch_mut::>>() { - handles.retain(|link| if L::persist(link, state.ecs().system_data()) { - true - } else { - L::delete(link, state.ecs().system_data()); - false + handles.retain(|link| { + if L::persist(link, state.ecs().system_data()) { + true + } else { + L::delete(link, state.ecs().system_data()); + false + } }); } } diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 300a4faab9..7eb9f641ac 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -27,6 +27,8 @@ use common::{ consts::GRAVITY, effect::{BuffEffect, Effect}, event::{Emitter, EventBus, ServerEvent}, + link::Is, + mounting::Mount, path::TraversalConfig, resources::{DeltaTime, Time, TimeOfDay}, rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent}, @@ -37,8 +39,6 @@ use common::{ uid::{Uid, UidAllocator}, util::Dir, vol::ReadVol, - mounting::Mount, - link::Is, }; use common_base::prof_span; use common_ecs::{Job, Origin, ParMode, Phase, System}; @@ -1428,18 +1428,16 @@ impl<'a> AgentData<'a> { /// Attempt to consume a healing item, and return whether any healing items /// were queued. Callers should use this to implement a delay so that - /// the healing isn't interrupted. If `relaxed` is `true`, we allow eating food and prioritise healing. + /// the healing isn't interrupted. If `relaxed` is `true`, we allow eating + /// food and prioritise healing. fn heal_self(&self, _agent: &mut Agent, controller: &mut Controller, relaxed: bool) -> bool { let healing_value = |item: &Item| { let mut value = 0.0; - if let ItemKind::Consumable { - kind, - effects, - .. - } = &item.kind - { - if matches!(kind, ConsumableKind::Drink) || (relaxed && matches!(kind, ConsumableKind::Food)) { + if let ItemKind::Consumable { kind, effects, .. } = &item.kind { + if matches!(kind, ConsumableKind::Drink) + || (relaxed && matches!(kind, ConsumableKind::Food)) + { for effect in effects.iter() { use BuffKind::*; match effect { @@ -1449,8 +1447,8 @@ impl<'a> AgentData<'a> { Effect::Buff(BuffEffect { kind, data, .. }) if matches!(kind, Regeneration | Saturation | Potion) => { - value += - data.strength * data.duration.map_or(0.0, |d| d.as_secs() as f32); + value += data.strength + * data.duration.map_or(0.0, |d| d.as_secs() as f32); }, _ => {}, } @@ -1469,10 +1467,12 @@ impl<'a> AgentData<'a> { }) .collect(); - consumables.sort_by_key(|(_, item)| if relaxed { - -healing_value(item) - } else { - healing_value(item) + consumables.sort_by_key(|(_, item)| { + if relaxed { + -healing_value(item) + } else { + healing_value(item) + } }); if let Some((id, _)) = consumables.last() { diff --git a/server/src/sys/entity_sync.rs b/server/src/sys/entity_sync.rs index af3261afc6..b15dbf8682 100644 --- a/server/src/sys/entity_sync.rs +++ b/server/src/sys/entity_sync.rs @@ -7,14 +7,14 @@ use crate::{ use common::{ calendar::Calendar, comp::{Collider, ForceUpdate, Inventory, InventoryUpdate, Last, Ori, Player, Pos, Vel}, + link::Is, + mounting::Rider, outcome::Outcome, region::{Event as RegionEvent, RegionMap}, resources::{PlayerPhysicsSettings, TimeOfDay}, terrain::TerrainChunkSize, uid::Uid, vol::RectVolSize, - link::Is, - mounting::Rider, }; use common_ecs::{Job, Origin, Phase, System}; use common_net::{msg::ServerGeneral, sync::CompSyncPackage}; diff --git a/server/src/sys/sentinel.rs b/server/src/sys/sentinel.rs index 00abaa293a..bae8b38b6b 100644 --- a/server/src/sys/sentinel.rs +++ b/server/src/sys/sentinel.rs @@ -2,13 +2,13 @@ use common::{ comp::{ item::{tool::AbilityMap, MaterialStatManifest}, - ActiveAbilities, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, - Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, - Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, Alignment, + ActiveAbilities, Alignment, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, + Collider, Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass, Ori, + Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel, }, - uid::Uid, - mounting::{Mount, Rider}, link::Is, + mounting::{Mount, Rider}, + uid::Uid, }; use common_ecs::{Job, Origin, Phase, System}; use common_net::{ diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 03494facb8..edb323bc3e 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -83,6 +83,8 @@ use common::{ BuffData, BuffKind, Item, }, consts::MAX_PICKUP_RANGE, + link::Is, + mounting::Mount, outcome::Outcome, slowjob::SlowJobPool, terrain::{SpriteKind, TerrainChunk}, @@ -90,8 +92,6 @@ use common::{ uid::Uid, util::{srgba_to_linear, Dir}, vol::RectRasterableVol, - mounting::Mount, - link::Is, }; use common_base::{prof_span, span}; use common_net::{ @@ -1668,32 +1668,33 @@ impl Hud { let mut sct_bg_walker = self.ids.sct_bgs.walk(); let pulse = self.pulse; - let make_overitem = |item: &Item, pos, distance, properties, fonts, interaction_options| { - let text = if item.amount() > 1 { - format!("{} x {}", item.amount(), item.name()) - } else { - item.name().to_string() + let make_overitem = + |item: &Item, pos, distance, properties, fonts, interaction_options| { + let text = if item.amount() > 1 { + format!("{} x {}", item.amount(), item.name()) + } else { + item.name().to_string() + }; + + let quality = get_quality_col(item); + + // Item + overitem::Overitem::new( + text.into(), + quality, + distance, + fonts, + i18n, + &global_state.settings.controls, + properties, + pulse, + &global_state.window.key_layout, + interaction_options, + ) + .x_y(0.0, 100.0) + .position_ingame(pos) }; - let quality = get_quality_col(item); - - // Item - overitem::Overitem::new( - text.into(), - quality, - distance, - fonts, - i18n, - &global_state.settings.controls, - properties, - pulse, - &global_state.window.key_layout, - interaction_options, - ) - .x_y(0.0, 100.0) - .position_ingame(pos) - }; - self.failed_block_pickups .retain(|_, t| pulse - *t < overitem::PICKUP_FAILED_FADE_OUT_TIME); self.failed_entity_pickups @@ -1788,7 +1789,22 @@ impl Hud { let speech_bubbles = &self.speech_bubbles; // Render overhead name tags and health bars - for (entity, pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group, dist_sqr, alignment, is_mount) in ( + for ( + entity, + pos, + info, + bubble, + _, + _, + health, + _, + height_offset, + hpfl, + in_group, + dist_sqr, + alignment, + is_mount, + ) in ( &entities, &pos, interpolated.maybe(), @@ -1932,16 +1948,23 @@ impl Hud { &global_state.window.key_layout, match alignment { // TODO: Don't use `MAX_MOUNT_RANGE` here, add dedicated interaction range - Some(comp::Alignment::Npc) if dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) - && interactable.as_ref().and_then(|i| i.entity()) == Some(entity) => + Some(comp::Alignment::Npc) + if dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) + && interactable.as_ref().and_then(|i| i.entity()) + == Some(entity) => + { vec![ (GameInput::Interact, i18n.get("hud.talk").to_string()), (GameInput::Trade, i18n.get("hud.trade").to_string()), - ], - Some(comp::Alignment::Owned(owner)) if Some(*owner) == client.uid() - && is_mount.is_none() - && dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) => - vec![(GameInput::Mount, i18n.get("hud.mount").to_string())], + ] + }, + Some(comp::Alignment::Owned(owner)) + if Some(*owner) == client.uid() + && is_mount.is_none() + && dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) => + { + vec![(GameInput::Mount, i18n.get("hud.mount").to_string())] + }, _ => Vec::new(), }, ) diff --git a/voxygen/src/hud/overhead.rs b/voxygen/src/hud/overhead.rs index b8e754b43a..e60d17d653 100644 --- a/voxygen/src/hud/overhead.rs +++ b/voxygen/src/hud/overhead.rs @@ -9,15 +9,15 @@ use crate::{ settings::{ControlSettings, InterfaceSettings}, ui::{fonts::Fonts, Ingameable}, }; -use keyboard_keynames::key_layout::KeyLayout; use common::comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType}; use conrod_core::{ color, position::Align, - widget::{self, Image, Rectangle, Text, RoundedRectangle}, + widget::{self, Image, Rectangle, RoundedRectangle, Text}, widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon, }; use i18n::Localization; +use keyboard_keynames::key_layout::KeyLayout; const MAX_BUBBLE_WIDTH: f64 = 250.0; widget_ids! { @@ -101,6 +101,7 @@ pub struct Overhead<'a> { } impl<'a> Overhead<'a> { + #[allow(clippy::too_many_arguments)] pub fn new( info: Option>, bubble: Option<&'a SpeechBubble>, @@ -467,25 +468,30 @@ impl<'a> Widget for Overhead<'a> { // Interaction hints if !self.interaction_options.is_empty() { - let text = self.interaction_options + let text = self + .interaction_options .iter() - .filter_map(|(input, action)| Some((self - .controls - .get_binding(*input)?, action))) - .map(|(input, action)| format!("{} {}", input.display_string(self.key_layout).as_str(), action)) + .filter_map(|(input, action)| { + Some((self.controls.get_binding(*input)?, action)) + }) + .map(|(input, action)| { + format!( + "{} {}", + input.display_string(self.key_layout).as_str(), + action + ) + }) .collect::>() .join("\n"); let scale = 30.0; let btn_rect_size = scale * 0.8; let btn_font_size = scale * 0.6; - let btn_rect_pos_y = 0.0; - let btn_text_pos_y = btn_rect_pos_y + ((btn_rect_size - btn_font_size) * 0.5); let btn_radius = btn_rect_size / 5.0; let btn_color = Color::Rgba(0.0, 0.0, 0.0, 0.8); - // RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius, btn_color) - // .x_y(0.0, btn_rect_pos_y) + // RoundedRectangle::fill_with([btn_rect_size, btn_rect_size], btn_radius, + // btn_color) .x_y(0.0, btn_rect_pos_y) // .depth(self.distance_from_player_sqr + 2.0) // .parent(id) // .set(state.ids.btn_bg, ui); @@ -494,11 +500,20 @@ impl<'a> Widget for Overhead<'a> { .font_size(btn_font_size as u32) .color(TEXT_COLOR) .parent(id) - .down_from(self.info.map_or(state.ids.name, |info| if info.health.map_or(false, should_show_healthbar) { - if info.energy.is_some() { state.ids.mana_bar } else { state.ids.health_bar } - } else { - state.ids.name - }), 12.0) + .down_from( + self.info.map_or(state.ids.name, |info| { + if info.health.map_or(false, should_show_healthbar) { + if info.energy.is_some() { + state.ids.mana_bar + } else { + state.ids.health_bar + } + } else { + state.ids.name + } + }), + 12.0, + ) .align_middle_x_of(state.ids.name) .depth(1.0); @@ -506,12 +521,16 @@ impl<'a> Widget for Overhead<'a> { hints_text.set(state.ids.interaction_hints, ui); - RoundedRectangle::fill_with([w + btn_radius * 2.0, h + btn_radius * 2.0], btn_radius, btn_color) - .depth(2.0) - .middle_of(state.ids.interaction_hints) - .align_middle_y_of(state.ids.interaction_hints) - .parent(id) - .set(state.ids.interaction_hints_bg, ui); + RoundedRectangle::fill_with( + [w + btn_radius * 2.0, h + btn_radius * 2.0], + btn_radius, + btn_color, + ) + .depth(2.0) + .middle_of(state.ids.interaction_hints) + .align_middle_y_of(state.ids.interaction_hints) + .parent(id) + .set(state.ids.interaction_hints_bg, ui); } } // Speech bubble diff --git a/voxygen/src/hud/overitem.rs b/voxygen/src/hud/overitem.rs index 5e76012156..968405a783 100644 --- a/voxygen/src/hud/overitem.rs +++ b/voxygen/src/hud/overitem.rs @@ -6,7 +6,7 @@ use crate::{ use conrod_core::{ color, widget::{self, RoundedRectangle, Text}, - widget_ids, Color, Colorable, Positionable, Widget, WidgetCommon, Sizeable, + widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon, }; use i18n::Localization; use std::borrow::Cow; @@ -172,13 +172,24 @@ impl<'a> Widget for Overitem<'a> { // Interaction hints if !self.interaction_options.is_empty() { - let text = self.interaction_options + let text = self + .interaction_options .iter() - .filter_map(|(input, action)| Some((self - .controls - .get_binding(*input) - .filter(|_| self.properties.active)?, action))) - .map(|(input, action)| format!("{} {}", input.display_string(self.key_layout).as_str(), action)) + .filter_map(|(input, action)| { + Some(( + self.controls + .get_binding(*input) + .filter(|_| self.properties.active)?, + action, + )) + }) + .map(|(input, action)| { + format!( + "{} {}", + input.display_string(self.key_layout).as_str(), + action + ) + }) .collect::>() .join("\n"); @@ -194,11 +205,15 @@ impl<'a> Widget for Overitem<'a> { hints_text.set(state.ids.btn, ui); - RoundedRectangle::fill_with([w + btn_radius * 2.0, h + btn_radius * 2.0], btn_radius, btn_color) - .x_y(0.0, btn_rect_pos_y) - .depth(self.distance_from_player_sqr + 2.0) - .parent(id) - .set(state.ids.btn_bg, ui); + RoundedRectangle::fill_with( + [w + btn_radius * 2.0, h + btn_radius * 2.0], + btn_radius, + btn_color, + ) + .x_y(0.0, btn_rect_pos_y) + .depth(self.distance_from_player_sqr + 2.0) + .parent(id) + .set(state.ids.btn_bg, ui); } if let Some(time) = self.properties.pickup_failed_pulse { //should never exceed 1.0, but just in case diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index b544460791..306f518665 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -35,13 +35,13 @@ use common::{ Body, CharacterState, Collider, Controller, Health, Inventory, Item, Last, LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Vel, }, + link::Is, + mounting::Rider, resources::{DeltaTime, Time}, states::{equipping, idle, utils::StageSection, wielding}, terrain::TerrainChunk, uid::UidAllocator, vol::RectRasterableVol, - link::Is, - mounting::Rider, }; use common_base::span; use common_state::State; @@ -489,8 +489,15 @@ impl FigureMgr { .and_then(|body| self.states.get_mut(body, &entity)) .and_then(|state| { // Calculate the correct lantern position - let pos = anim::vek::Vec3::from(interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array()); - Some(state.mount_world_pos + state.mount_transform.orientation * anim::vek::Vec3::from(state.lantern_offset?.into_array()) - pos) + let pos = anim::vek::Vec3::from( + interpolated.map(|i| i.pos).unwrap_or(pos.0).into_array(), + ); + Some( + state.mount_world_pos + + state.mount_transform.orientation + * anim::vek::Vec3::from(state.lantern_offset?.into_array()) + - pos, + ) }) { light_anim.offset = vek::Vec3::from(lantern_offset); @@ -739,7 +746,9 @@ impl FigureMgr { let (in_frustum, lpindex) = if let Some(ref mut meta) = state { let (in_frustum, lpindex) = BoundingSphere::new(pos.0.into_array(), radius) .coherent_test_against_frustum(frustum, meta.lpindex); - let in_frustum = in_frustum || matches!(body, Body::Ship(_)); + let in_frustum = in_frustum + || matches!(body, Body::Ship(_)) + || pos.0.distance_squared(focus_pos) < 32.0f32.powi(2); meta.visible = in_frustum; meta.lpindex = lpindex; if in_frustum { diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 7b047da0db..a028df181e 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -22,13 +22,13 @@ use common::{ ChatMsg, ChatType, InputKind, InventoryUpdateEvent, Pos, Stats, UtteranceKind, Vel, }, consts::MAX_MOUNT_RANGE, + link::Is, + mounting::Mount, outcome::Outcome, terrain::{Block, BlockKind}, trade::TradeResult, util::{Dir, Plane}, vol::ReadVol, - link::Is, - mounting::{Mounting, Mount}, }; use common_base::{prof_span, span}; use common_net::{ @@ -687,10 +687,12 @@ impl PlayState for SessionState { &client.state().ecs().read_storage::(), // TODO: More cleverly filter by things that can actually be mounted !&client.state().ecs().read_storage::>(), + client.state().ecs().read_storage::().maybe(), ) .join() - .filter(|(entity, _, _)| *entity != client.entity()) - .map(|(entity, pos, _)| { + .filter(|(entity, _, _, _)| *entity != client.entity()) + .filter(|(_, _, _, alignment)| matches!(alignment, Some(comp::Alignment::Owned(owner)) if Some(*owner) == client.uid())) + .map(|(entity, pos, _, _)| { (entity, player_pos.0.distance_squared(pos.0)) }) .filter(|(_, dist_sqr)| {