From bf6ac56eb049549186cf977e8b9e8126fc129fa4 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Wed, 14 Apr 2021 17:55:19 -0400 Subject: [PATCH] Add teleport/speedhack mitigation. --- CHANGELOG.md | 2 ++ server/src/sys/msg/in_game.rs | 50 +++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0d6f277dd..6eb859a105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added /disconnect_all_players admin command - Added disconnectall CLI command - One handed weapons can now be used and found in the world +- Players can now opt-in to server-authoritiative physics in gameplay settings. ### Changed @@ -56,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Item tooltips during trades will now inform the user of what ctrl-click and shift-click do - International keyboards can now display more key names on Linux and Windows instead of `Unknown`. - There is now a brief period after a character leaves the world where they cannot rejoin until their data is saved +- Certain uses of client-authoritative physics now subject the player to server-authoritative physics. ### Removed diff --git a/server/src/sys/msg/in_game.rs b/server/src/sys/msg/in_game.rs index a8dc2b8a6b..5e448648af 100644 --- a/server/src/sys/msg/in_game.rs +++ b/server/src/sys/msg/in_game.rs @@ -12,7 +12,7 @@ use common_ecs::{Job, Origin, Phase, System}; use common_net::msg::{ClientGeneral, PresenceKind, ServerGeneral}; use common_sys::state::{BlockChange, BuildAreas}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage}; -use tracing::{debug, trace}; +use tracing::{debug, trace, warn}; impl Sys { #[allow(clippy::too_many_arguments)] @@ -107,11 +107,51 @@ impl Sys { if matches!(presence.kind, PresenceKind::Character(_)) && force_updates.get(entity).is_none() && healths.get(entity).map_or(true, |h| !h.is_dead) - && player_physics_setting.map_or(true, |s| s.client_authoritative()) + && player_physics_setting + .as_ref() + .map_or(true, |s| s.client_authoritative()) { - let _ = positions.insert(entity, pos); - let _ = velocities.insert(entity, vel); - let _ = orientations.insert(entity, ori); + let mut reject_update = false; + if let Some(mut setting) = player_physics_setting { + // If we detect any thresholds being exceeded, force server-authoritative + // physics for that player. This doesn't detect subtle hacks, but it + // prevents blatent ones and forces people to not debug physics hacks on the + // live server (and also mitigates some floating-point overflow crashes) + if let Some(prev_pos) = positions.get(entity) { + let value_squared = prev_pos.0.distance_squared(pos.0); + if value_squared > (500.0f32).powf(2.0) { + setting.server_optout = true; + reject_update = true; + warn!( + "PlayerPhysics position exceeded {:?} {:?} {:?}", + prev_pos, + pos, + value_squared.sqrt() + ); + } + } + + if vel.0.magnitude_squared() > (500.0f32).powf(2.0) { + setting.server_optout = true; + reject_update = true; + warn!( + "PlayerPhysics velocity exceeded {:?} {:?}", + pos, + vel.0.magnitude() + ); + } + } + + if reject_update { + warn!( + "Rejected PlayerPhysics update {:?} {:?} {:?} {:?}", + pos, vel, ori, maybe_player + ); + } else { + let _ = positions.insert(entity, pos); + let _ = velocities.insert(entity, vel); + let _ = orientations.insert(entity, ori); + } } }, ClientGeneral::BreakBlock(pos) => {