Fix anticheat resetting client position after the client is teleported
authorEkdohibs <nathanael.courant@laposte.net>
Mon, 30 Jan 2017 06:58:43 +0000 (07:58 +0100)
committerparamat <mat.gregory@virginmedia.com>
Wed, 1 Feb 2017 15:03:57 +0000 (15:03 +0000)
Previously, m_move_pool could accomodate the client moving from the new
position to the old one, and the server accepted the client to go back
to its old position. However, it couldn't then accomodate the client
moving from its old to its new position, and therefore would reset position
to the old position. Thus, by emptying m_move_pool after a teleport, the
server no longer accepts the client to go back to its old position. A
drawback is however that a laggy client *will* trigger a few
"moved_too_fast" anticheats before being told about its new position.

Don't report player cheated if caused by lag.

Fixes #5118

src/content_sao.cpp
src/content_sao.h

index 7a1171eb70427790afa07ce28985e980fe88c25c..f87977f800e2b18d6bd8e3ef423931a0475033e2 100644 (file)
@@ -785,6 +785,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer
        m_inventory(NULL),
        m_damage(0),
        m_last_good_position(0,0,0),
+       m_time_from_last_teleport(0),
        m_time_from_last_punch(0),
        m_nocheat_dig_pos(32767, 32767, 32767),
        m_nocheat_dig_time(0),
@@ -1000,6 +1001,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
        // Increment cheat prevention timers
        m_dig_pool.add(dtime);
        m_move_pool.add(dtime);
+       m_time_from_last_teleport += dtime;
        m_time_from_last_punch += dtime;
        m_nocheat_dig_time += dtime;
 
@@ -1106,6 +1108,8 @@ void PlayerSAO::setPos(const v3f &pos)
        setBasePosition(pos);
        // Movement caused by this command is always valid
        m_last_good_position = pos;
+       m_move_pool.empty();
+       m_time_from_last_teleport = 0.0;
        m_env->getGameDef()->SendMovePlayer(m_peer_id);
 }
 
@@ -1117,6 +1121,8 @@ void PlayerSAO::moveTo(v3f pos, bool continuous)
        setBasePosition(pos);
        // Movement caused by this command is always valid
        m_last_good_position = pos;
+       m_move_pool.empty();
+       m_time_from_last_teleport = 0.0;
        m_env->getGameDef()->SendMovePlayer(m_peer_id);
 }
 
@@ -1405,11 +1411,16 @@ bool PlayerSAO::checkMovementCheat()
        if (m_move_pool.grab(required_time)) {
                m_last_good_position = m_base_position;
        } else {
-               actionstream << "Player " << m_player->getName()
-                               << " moved too fast; resetting position"
-                               << std::endl;
+               const float LAG_POOL_MIN = 5.0;
+               float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
+               lag_pool_max = MYMAX(lag_pool_max, LAG_POOL_MIN);
+               if (m_time_from_last_teleport > lag_pool_max) {
+                       actionstream << "Player " << m_player->getName()
+                                       << " moved too fast; resetting position"
+                                       << std::endl;
+                       cheated = true;
+               }
                setBasePosition(m_last_good_position);
-               cheated = true;
        }
        return cheated;
 }
index bbf244742c5b56bcd7928779bfa37827717be780..1ccea0d7808f115c2161f0d468c656880f107ca4 100644 (file)
@@ -157,18 +157,26 @@ class LagPool
 public:
        LagPool(): m_pool(15), m_max(15)
        {}
+
        void setMax(float new_max)
        {
                m_max = new_max;
                if(m_pool > new_max)
                        m_pool = new_max;
        }
+
        void add(float dtime)
        {
                m_pool -= dtime;
                if(m_pool < 0)
                        m_pool = 0;
        }
+
+       void empty()
+       {
+               m_pool = m_max;
+       }
+
        bool grab(float dtime)
        {
                if(dtime <= 0)
@@ -358,6 +366,7 @@ private:
        LagPool m_dig_pool;
        LagPool m_move_pool;
        v3f m_last_good_position;
+       float m_time_from_last_teleport;
        float m_time_from_last_punch;
        v3s16 m_nocheat_dig_pos;
        float m_nocheat_dig_time;