diff --git a/CHANGELOG.md b/CHANGELOG.md index c3495c3ed1..f73fd13325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Falling through an airship in flight should no longer be possible (although many issues with airship physics remain) - Avoided black hexagons when bloom is enabled by suppressing NaN/Inf pixels during the first bloom blur pass - Many know water generation problems +- Trading over long distances using ghost characters or client-side exploits is no longer possible ## [0.11.0] - 2021-09-11 diff --git a/common/src/consts.rs b/common/src/consts.rs index 00afd49eaa..591e068df7 100644 --- a/common/src/consts.rs +++ b/common/src/consts.rs @@ -1,6 +1,7 @@ // The limit on distance between the entity and a collectible (squared) pub const MAX_PICKUP_RANGE: f32 = 5.0; pub const MAX_MOUNT_RANGE: f32 = 14.0; +pub const MAX_TRADE_RANGE: f32 = 20.0; pub const GRAVITY: f32 = 25.0; pub const FRIC_GROUND: f32 = 0.15; diff --git a/server/src/events/invite.rs b/server/src/events/invite.rs index 1fd56d2ba5..47b01728bd 100644 --- a/server/src/events/invite.rs +++ b/server/src/events/invite.rs @@ -6,8 +6,9 @@ use common::{ agent::{Agent, AgentEvent}, group::GroupManager, invite::{Invite, InviteKind, InviteResponse, PendingInvites}, - ChatType, + ChatType, Pos, }, + consts::MAX_TRADE_RANGE, trade::{TradeResult, Trades}, uid::Uid, }; @@ -63,6 +64,14 @@ pub fn handle_invite( let mut agents = state.ecs().write_storage::(); let mut invites = state.ecs().write_storage::(); + if let InviteKind::Trade = kind { + // Check whether the inviter is in range of the invitee + let positions = state.ecs().read_storage::(); + if !within_trading_range(positions.get(inviter), positions.get(invitee)) { + return; + } + } + if let InviteKind::Group = kind { if !group_manip::can_invite( state, @@ -336,3 +345,10 @@ pub fn handle_invite_decline(server: &mut Server, entity: specs::Entity) { handle_invite_answer(state, inviter, entity, InviteAnswer::Declined, kind) } } + +fn within_trading_range(requester_position: Option<&Pos>, invitee_position: Option<&Pos>) -> bool { + match (requester_position, invitee_position) { + (Some(rpos), Some(ipos)) => rpos.0.distance_squared(ipos.0) < MAX_TRADE_RANGE.powi(2), + _ => false, + } +}