Browse Source

intelligent client server player position sync (anticheat)

Kajetan Johannes Hammerle 2 months ago
parent
commit
6cc05eb2b3

+ 24 - 6
client/Game.cpp

@@ -6,6 +6,7 @@
 #include "common/network/toserver/PlayerUpdatePacket.h"
 #include "rendering/renderer/WorldRenderer.h"
 #include "utils/Logger.h"
+#include "utils/Random.h"
 #include "utils/Utils.h"
 
 BlockRegistry Game::blockRegistry;
@@ -21,6 +22,9 @@ static State renderState;
 static BaseGUI baseGUI;
 static StartGUI startGUI;
 
+static List<PlayerUpdatePacket> delay;
+static Random rng;
+
 static void tickConnectedState() {
     Game::player.skip = false;
     Game::world.tick();
@@ -51,10 +55,11 @@ static void tickConnectedState() {
     if(force.squareLength() > 0.0f) {
         force.normalize();
     }
-    Game::player.addForce(force * 0.1f);
+    Game::player.addForce(force * Game::player.speed);
 
     if(Game::controller.jump.isDown() && Game::player.isOnGround()) {
-        Game::player.addForce(up * (0.42f / 0.98f + 0.08f));
+        Game::player.jump();
+        // Game::player.acceleration[1] += 0.4;
     }
     if(Game::controller.camLeft.isDown()) {
         Game::player.addLengthAngle(-rotationSpeed);
@@ -69,10 +74,21 @@ static void tickConnectedState() {
         Game::player.addWidthAngle(rotationSpeed * 0.5f);
     }
 
-    PlayerUpdatePacket p(Game::player);
-    OutPacket out = OutPacket::sequenced(PlayerUpdatePacket::getSize());
-    p.write(out);
-    GameClient::send(out);
+    delay.add(PlayerUpdatePacket(Game::player));
+    if(rng.nextFloat() < 0.5f) {
+        OutPacket out = OutPacket::reliable(PlayerUpdatePacket::getSize());
+        delay[0].write(out);
+        GameClient::send(out);
+        delay.remove(0);
+
+        if(delay.getLength() > 0) {
+            OutPacket out = OutPacket::reliable(PlayerUpdatePacket::getSize());
+            delay[0].write(out);
+            GameClient::send(out);
+            delay.remove(0);
+        }
+    }
+    LOG_DEBUG(delay.getLength());
 }
 
 static void renderConnectedState() {
@@ -138,4 +154,6 @@ void Game::renderOverlay() {
 void Game::onEntityUpdate(EntityUpdatePacket& p) {
     LOG_DEBUG("set");
     player.setPosition(p.position);
+    player.velocity = p.velocity;
+    delay.clear();
 }

+ 20 - 6
common/entities/Entity.cpp

@@ -1,10 +1,13 @@
 #include "common/entities/Entity.h"
 #include "utils/Utils.h"
 
+static constexpr float GRAVITY = -0.08f;
+
 Entity::Entity()
     : lastLengthAngle(0.0f), lengthAngle(0.0f), lastWidthAngle(0.0f),
-      widthAngle(0.0f), size(Vector3(0.5f, 1.8f, 0.5f)), onGround(false),
-      skip(false) {
+      widthAngle(0.0f), size(Vector3(0.5f, 1.8f, 0.5f)),
+      drag(0.686f, 0.98f, 0.686f), speed(0.1f), jumpPower(0.42f),
+      onGround(false), skip(false) {
 }
 
 void Entity::tick() {
@@ -13,10 +16,10 @@ void Entity::tick() {
     lastWidthAngle = widthAngle;
 
     velocity += acceleration;
-    velocity[0] *= 0.686f;
-    velocity[1] *= 0.98f;
-    velocity[2] *= 0.686f;
-    acceleration = Vector3(0.0f, -0.08f, 0.0f);
+    velocity[0] *= drag[0];
+    velocity[1] *= drag[1];
+    velocity[2] *= drag[2];
+    acceleration = Vector3(0.0f, GRAVITY, 0.0f);
 }
 
 void Entity::addForce(const Vector3& force) {
@@ -91,4 +94,15 @@ void Entity::addWidthAngle(float angle) {
     constexpr float border = 89.9f;
     widthAngle += angle;
     widthAngle = std::min(std::max(widthAngle + angle, -border), border);
+}
+
+float Entity::getMaxXZVelocity() const {
+    float f = std::min(drag[0], drag[2]);
+    return f * speed / (1 - f);
+}
+
+void Entity::jump() {
+    if(onGround) {
+        acceleration[1] += (jumpPower / drag[1] - GRAVITY);
+    }
 }

+ 6 - 0
common/entities/Entity.h

@@ -14,6 +14,9 @@ struct Entity {
     Vector3 velocity;
     Vector3 acceleration;
     Vector3 size;
+    Vector3 drag;
+    float speed;
+    float jumpPower;
     bool onGround;
     bool skip;
 
@@ -35,6 +38,9 @@ struct Entity {
     Quaternion getRenderRotation(float lag) const;
     void addLengthAngle(float angle);
     void addWidthAngle(float angle);
+
+    float getMaxXZVelocity() const;
+    void jump();
 };
 
 #endif

+ 4 - 2
common/network/toclient/EntityUpdatePacket.cpp

@@ -3,7 +3,7 @@
 
 EntityUpdatePacket::EntityUpdatePacket(const Entity& e)
     : lengthAngle(e.lengthAngle), widthAngle(e.widthAngle),
-      position(e.position) {
+      position(e.position), velocity(e.velocity) {
 }
 
 EntityUpdatePacket::EntityUpdatePacket() {
@@ -14,11 +14,13 @@ void EntityUpdatePacket::write(OutPacket& out) const {
     out.writeFloat(lengthAngle);
     out.writeFloat(widthAngle);
     Packets::writeVector(out, position);
+    Packets::writeVector(out, velocity);
 }
 
 bool EntityUpdatePacket::read(InPacket& in) {
     return in.readFloat(lengthAngle) || in.readFloat(widthAngle) ||
-           Packets::readVector(in, position);
+           Packets::readVector(in, position) ||
+           Packets::readVector(in, velocity);
 }
 
 int EntityUpdatePacket::getSize() {

+ 1 - 0
common/network/toclient/EntityUpdatePacket.h

@@ -9,6 +9,7 @@ struct EntityUpdatePacket {
     float lengthAngle;
     float widthAngle;
     Vector3 position;
+    Vector3 velocity;
 
     EntityUpdatePacket(const Entity& e);
     EntityUpdatePacket();

+ 4 - 2
common/world/World.cpp

@@ -62,8 +62,10 @@ List<CollisionBox> World::getBoxes(const CollisionBox& box) const {
 void World::tick() {
     for(Entity* e : entities) {
         e->tick();
-        Vector3 move = limitMove(*e, e->getVelocity());
-        e->move(move);
+        if(!e->skip) {
+            Vector3 move = limitMove(*e, e->getVelocity());
+            e->move(move);
+        }
     }
 }
 

+ 39 - 13
server/entities/ServerPlayer.cpp

@@ -5,28 +5,44 @@
 #include "utils/Logger.h"
 
 ServerPlayer::ServerPlayer(Server::Client& client) : client(client) {
+    skip = true;
 }
 
 void ServerPlayer::tick() {
     if(!history.canRead()) {
+        LOG_DEBUG("No data");
         return;
     }
-    Entity::tick();
-
     PlayerUpdatePacket p = history.read();
 
     Vector3 move = p.position - position;
-    Vector3 actualMove = Game::world.limitMove(*this, move);
-
-    float diff = (move - actualMove).squareLength();
-    if(diff > 0.1f) {
-        EntityUpdatePacket e(*this);
-        OutPacket out = OutPacket::sequenced(EntityUpdatePacket::getSize());
-        e.write(out);
-        GameServer::sendToAll(out);
-    } else {
-        this->move(actualMove);
+    float xzDistance = Vector2(move[0], move[2]).squareLength();
+    float maxXZDistance = getMaxXZVelocity();
+    maxXZDistance *= maxXZDistance;
+    maxXZDistance *= 1.01f;
+    if(xzDistance > maxXZDistance) {
+        setClientPosition();
+        return;
+    }
+    if(move[1] > 0.4f) {
+        jump();
+    }
+    Entity::tick();
+
+    Vector3 actualClientMove = Game::world.limitMove(*this, move);
+    Vector3 actualServerMove =
+        Game::world.limitMove(*this, Vector3(move[0], velocity[1], move[2]));
+
+    float distance = (actualClientMove - actualServerMove).squareLength();
+    if(distance > 0.001f) {
+        actualClientMove = actualServerMove;
+    }
+    this->move(actualClientMove);
+    if((move - actualClientMove).squareLength() > 0.05f) {
+        setClientPosition();
     }
+    velocity[0] = 0.0f;
+    velocity[2] = 0.0f;
 }
 
 void ServerPlayer::onChat(InPacket& in) {
@@ -38,5 +54,15 @@ void ServerPlayer::send(OutPacket& out) {
 }
 
 void ServerPlayer::onUpdatePacket(const PlayerUpdatePacket& p) {
-    history.write(p);
+    if(history.write(p)) {
+        LOG_WARNING("FULL QUEUE");
+    }
+}
+
+void ServerPlayer::setClientPosition() {
+    history.clear();
+    EntityUpdatePacket e(*this);
+    OutPacket out = OutPacket::sequenced(EntityUpdatePacket::getSize());
+    e.write(out);
+    GameServer::sendToAll(out);
 }

+ 4 - 1
server/entities/ServerPlayer.h

@@ -8,7 +8,7 @@
 
 class ServerPlayer : public Entity {
     Server::Client& client;
-    RingBuffer<PlayerUpdatePacket, 5> history;
+    RingBuffer<PlayerUpdatePacket, 40> history;
 
 public:
     ServerPlayer(Server::Client& client);
@@ -18,6 +18,9 @@ public:
     void sendChunk();
     void send(OutPacket& out);
     void onUpdatePacket(const PlayerUpdatePacket& p);
+
+private:
+    void setClientPosition();
 };
 
 #endif

+ 1 - 1
subprojects/gaming-core

@@ -1 +1 @@
-Subproject commit eb3c259056e17f8772986c786343ca563123c81e
+Subproject commit 14d9f19f59b6f90a8d107f8a0005d9e600758d32