Browse Source

buggy player client server sync

Kajetan Johannes Hammerle 2 years ago
parent
commit
aa8d558037

+ 71 - 46
client/Game.cpp

@@ -3,6 +3,7 @@
 #include "client/gui/StartGUI.h"
 #include "client/rendering/Engine.h"
 #include "common/network/Packets.h"
+#include "common/network/toserver/ControllerPacket.h"
 #include "rendering/renderer/WorldRenderer.h"
 #include "utils/Logger.h"
 #include "utils/Utils.h"
@@ -11,7 +12,7 @@ BlockRegistry Game::blockRegistry;
 World Game::world{blockRegistry};
 static WorldRenderer worldRenderer{Game::world};
 Controller Game::controller;
-Player Game::player;
+Entity Game::player;
 
 typedef void (*State)();
 static State tickState;
@@ -21,8 +22,63 @@ static BaseGUI baseGUI;
 static StartGUI startGUI;
 
 static void tickConnectedState() {
-    GameClient::consumeEvents();
+    Game::player.skip = false;
     Game::world.tick();
+    GameClient::consumeEvents();
+
+    Quaternion q = Game::player.getRotation();
+
+    Vector3 up(0.0f, 1.0f, 0.0f);
+    Vector3 back = q * Vector3(0.0f, 0.0f, -1.0f);
+    back[1] = 0.0f;
+    back.normalize();
+    Vector3 right = back.cross(up);
+
+    constexpr float speed = 0.1f;
+    constexpr float rotationSpeed = 4.0f;
+    ControllerPacket cp;
+    if(Game::controller.down.isDown()) {
+        cp.set(ControllerPacket::Type::DOWN);
+        Game::player.addForce(back * speed);
+    }
+    if(Game::controller.up.isDown()) {
+        cp.set(ControllerPacket::Type::UP);
+        Game::player.addForce(back * -speed);
+    }
+    if(Game::controller.left.isDown()) {
+        cp.set(ControllerPacket::Type::LEFT);
+        Game::player.addForce(right * -speed);
+    }
+    if(Game::controller.right.isDown()) {
+        cp.set(ControllerPacket::Type::RIGHT);
+        Game::player.addForce(right * speed);
+    }
+    if(Game::controller.jump.isDown() && Game::player.isOnGround()) {
+        cp.set(ControllerPacket::Type::JUMP);
+        Game::player.addForce(up * 0.5f);
+    }
+    if(Game::controller.sneak.isDown()) {
+        cp.set(ControllerPacket::Type::SNEAK);
+    }
+    if(Game::controller.camLeft.isDown()) {
+        cp.set(ControllerPacket::Type::CAM_LEFT);
+        Game::player.addLengthAngle(-rotationSpeed);
+    }
+    if(Game::controller.camRight.isDown()) {
+        cp.set(ControllerPacket::Type::CAM_RIGHT);
+        Game::player.addLengthAngle(rotationSpeed);
+    }
+    if(Game::controller.camUp.isDown()) {
+        cp.set(ControllerPacket::Type::CAM_UP);
+        Game::player.addWidthAngle(-rotationSpeed * 0.5f);
+    }
+    if(Game::controller.camDown.isDown()) {
+        cp.set(ControllerPacket::Type::CAM_DOWN);
+        Game::player.addWidthAngle(rotationSpeed * 0.5f);
+    }
+    OutPacket out = OutPacket::reliable(ControllerPacket::getSize());
+    cp.write(out);
+    GameClient::send(out);
 }
 
 static void renderConnectedState() {
@@ -55,55 +111,12 @@ bool Game::init() {
     tickState = tickConnectState;
     renderState = renderConnectState;
 
-    player.setPosition(Vector3(0.0f, 30.0f, 0.0f));
-    world.addPlayer(&player);
+    world.addEntity(&player);
     return false;
 }
 
 void Game::tick() {
     tickState();
-
-    Quaternion q = player.getRotation();
-
-    Vector3 up(0.0f, 1.0f, 0.0f);
-    Vector3 back = q * Vector3(0.0f, 0.0f, -1.0f);
-    back[1] = 0.0f;
-    back.normalize();
-    Vector3 right = back.cross(up);
-
-    constexpr float speed = 0.1f;
-    if(controller.down.isDown()) {
-        player.addForce(back * speed);
-    }
-    if(controller.up.isDown()) {
-        player.addForce(back * -speed);
-    }
-    if(controller.left.isDown()) {
-        player.addForce(right * -speed);
-    }
-    if(controller.right.isDown()) {
-        player.addForce(right * speed);
-    }
-    if(controller.jump.isDown() && player.isOnGround()) {
-        player.addForce(up * 0.5f);
-    }
-    if(controller.sneak.isDown()) {
-        player.addForce(up * -speed);
-    }
-
-    constexpr float rotationSpeed = 4.0f;
-    if(controller.camLeft.isDown()) {
-        player.addLengthAngle(-rotationSpeed);
-    }
-    if(controller.camRight.isDown()) {
-        player.addLengthAngle(rotationSpeed);
-    }
-    if(controller.camUp.isDown()) {
-        player.addWidthAngle(-rotationSpeed * 0.5f);
-    }
-    if(controller.camDown.isDown()) {
-        player.addWidthAngle(rotationSpeed * 0.5f);
-    }
 }
 
 void Game::renderWorld() {
@@ -121,4 +134,16 @@ void Game::renderOverlay() {
         .append(" &999TPS: &722")
         .append(Engine::getTickClock().getUpdatesPerSecond());
     Engine::renderer.renderString(Vector2(10.0f, 10.0f), s);
+}
+
+void Game::onEntityUpdate(EntityUpdatePacket& p) {
+    float distance = (p.position - player.position).squareLength();
+    StringBuffer<50>(distance).printLine();
+    if(distance > 25.0f) {
+        std::cout << "set\n";
+        player.setPosition(p.position);
+    }
+    // player.position = p.position;
+    // player.lengthAngle = p.lengthAngle;
+    // player.widthAngle = p.widthAngle;
 }

+ 5 - 2
client/Game.h

@@ -3,20 +3,23 @@
 
 #include "client/input/Controller.h"
 #include "common/block/BlockRegistry.h"
-#include "common/entities/Player.h"
+#include "common/entities/Entity.h"
+#include "common/network/toclient/EntityUpdatePacket.h"
 #include "common/world/World.h"
 
 namespace Game {
     extern BlockRegistry blockRegistry;
     extern World world;
     extern Controller controller;
-    extern Player player;
+    extern Entity player;
 
     bool init();
 
     void tick();
     void renderWorld();
     void renderOverlay();
+
+    void onEntityUpdate(EntityUpdatePacket& p);
 }
 
 #endif

+ 19 - 2
client/GameClient.cpp

@@ -4,8 +4,19 @@
 #include "common/network/Packets.h"
 #include "utils/Logger.h"
 
+static constexpr const char* INVALID_PACKAGE = "invalid package from server";
+
 static Client client;
 
+static void handleEntityUpdate(InPacket& in) {
+    EntityUpdatePacket p;
+    if(p.read(in)) {
+        LOG_WARNING(INVALID_PACKAGE);
+        return;
+    }
+    Game::onEntityUpdate(p);
+}
+
 struct Receiver {
     void onConnect() {
     }
@@ -19,16 +30,18 @@ struct Receiver {
             return;
         }
         switch(id) {
-            case S_CHAT:
+            case Packets::S_CHAT:
                 {
                     StringBuffer<256> s;
                     in.readString(s);
                     puts(s);
                     break;
                 }
-            case S_WORLD_SEGMENT:
+            case Packets::S_WORLD_SEGMENT:
                 WorldPackets::receiveChunk(Game::world, in);
                 break;
+            case Packets::S_ENTITY_UPDATE: handleEntityUpdate(in); break;
+            default: LOG_WARNING(INVALID_PACKAGE);
         }
     }
 };
@@ -48,4 +61,8 @@ Error GameClient::connect(const char* address, Client::Port port, int timeout) {
 void GameClient::consumeEvents() {
     Receiver r;
     client.consumeEvents(r);
+}
+
+void GameClient::send(OutPacket& out) {
+    client.send(out);
 }

+ 1 - 0
client/GameClient.h

@@ -7,6 +7,7 @@ namespace GameClient {
     bool init();
     Error connect(const char* address, Client::Port port, int timeout);
     void consumeEvents();
+    void send(OutPacket& out);
 }
 
 #endif

+ 2 - 0
client/gui/StartGUI.cpp

@@ -4,6 +4,8 @@
 StartGUI::StartGUI()
     : info(base.addLabel("Connect to server ...")), address(base.addInput()),
       connect(base.addButton("Connect ...")) {
+    address.text.setActive(true);
+    address.text.fill("127.0.0.1");
 }
 
 void StartGUI::tick() {

+ 25 - 24
common/entities/Player.cpp → common/entities/Entity.cpp

@@ -1,12 +1,13 @@
-#include "common/entities/Player.h"
+#include "common/entities/Entity.h"
 #include "utils/Utils.h"
 
-Player::Player()
+Entity::Entity()
     : lastLengthAngle(0.0f), lengthAngle(0.0f), lastWidthAngle(0.0f),
-      widthAngle(0.0f), size(Vector3(0.5f, 1.8f, 0.5f)) {
+      widthAngle(0.0f), size(Vector3(0.5f, 1.8f, 0.5f)), onGround(false),
+      skip(false) {
 }
 
-void Player::tick() {
+void Entity::tick() {
     lastPosition = position;
     lastLengthAngle = lengthAngle;
     lastWidthAngle = widthAngle;
@@ -18,54 +19,54 @@ void Player::tick() {
     acceleration = Vector3(0.0f, -0.08f, 0.0f);
 }
 
-void Player::addForce(const Vector3& force) {
+void Entity::addForce(const Vector3& force) {
     acceleration += force;
 }
 
-const Vector3& Player::getVelocity() const {
+const Vector3& Entity::getVelocity() const {
     return velocity;
 }
 
-void Player::move(const Vector3& v) {
+void Entity::move(const Vector3& v) {
     position += v;
     onGround = v[1] == 0.0f && velocity[1] < 0.0f;
     velocity = v;
 }
 
-CollisionBox Player::getCollisionBox() const {
+CollisionBox Entity::getCollisionBox() const {
     return CollisionBox(size).offset(position);
 }
 
-bool Player::isOnGround() const {
+bool Entity::isOnGround() const {
     return onGround;
 }
 
-void Player::setPosition(const Vector3& pos) {
+void Entity::setPosition(const Vector3& pos) {
     setPosition(pos, lengthAngle, widthAngle);
 }
 
-void Player::setPosition(const Vector3& pos, float lengthAngle,
+void Entity::setPosition(const Vector3& pos, float lengthAngle,
                          float widthAngle) {
-    Player::lastPosition = pos;
-    Player::position = pos;
-    Player::lastLengthAngle = lengthAngle;
-    Player::lengthAngle = lengthAngle;
-    Player::lastWidthAngle = widthAngle;
-    Player::widthAngle = widthAngle;
-    Player::velocity = Vector3();
-    Player::acceleration = Vector3();
+    Entity::lastPosition = pos;
+    Entity::position = pos;
+    Entity::lastLengthAngle = lengthAngle;
+    Entity::lengthAngle = lengthAngle;
+    Entity::lastWidthAngle = widthAngle;
+    Entity::widthAngle = widthAngle;
+    Entity::velocity = Vector3();
+    Entity::acceleration = Vector3();
 }
 
-Vector3 Player::getRenderPosition(float lag) const {
+Vector3 Entity::getRenderPosition(float lag) const {
     return Utils::interpolate(lastPosition, position, lag) +
            Vector3(size[0] * 0.5f, size[1], size[2] * 0.5f);
 }
 
-Quaternion Player::getRotation() const {
+Quaternion Entity::getRotation() const {
     return getRenderRotation(1.0f);
 }
 
-Quaternion Player::getRenderRotation(float lag) const {
+Quaternion Entity::getRenderRotation(float lag) const {
     float lAngle = Utils::interpolate(lastLengthAngle, lengthAngle, lag);
     float wAngle = Utils::interpolate(lastWidthAngle, widthAngle, lag);
     Quaternion q(Vector3(0.0f, 1.0f, 0.0f), lAngle);
@@ -73,7 +74,7 @@ Quaternion Player::getRenderRotation(float lag) const {
     return q;
 }
 
-void Player::addLengthAngle(float angle) {
+void Entity::addLengthAngle(float angle) {
     lengthAngle += angle;
     constexpr float full = 360.0f;
     while(lengthAngle < 0.0f) {
@@ -86,7 +87,7 @@ void Player::addLengthAngle(float angle) {
     }
 }
 
-void Player::addWidthAngle(float angle) {
+void Entity::addWidthAngle(float angle) {
     constexpr float border = 89.9f;
     widthAngle += angle;
     widthAngle = std::min(std::max(widthAngle + angle, -border), border);

+ 7 - 6
common/entities/Player.h → common/entities/Entity.h

@@ -1,10 +1,10 @@
-#ifndef PLAYER_H
-#define PLAYER_H
+#ifndef ENTITY_H
+#define ENTITY_H
 
 #include "common/utils/CollisionBox.h"
 #include "math/Quaternion.h"
 
-class Player {
+struct Entity {
     Vector3 lastPosition;
     Vector3 position;
     float lastLengthAngle;
@@ -15,11 +15,12 @@ class Player {
     Vector3 acceleration;
     Vector3 size;
     bool onGround;
+    bool skip;
 
-public:
-    Player();
+    Entity();
+    virtual ~Entity() = default;
 
-    void tick();
+    virtual void tick();
 
     void addForce(const Vector3& force);
     const Vector3& getVelocity() const;

+ 26 - 4
common/network/Packets.h

@@ -1,9 +1,31 @@
 #ifndef PACKETS_H
 #define PACKETS_H
 
-// packets from the server to clients
-enum ServerPacket { S_CHAT, S_WORLD_SEGMENT };
-// packets from clients to the server
-enum ClientPacket { C_CHAT };
+#include "math/Vector.h"
+#include "network/Packet.h"
+
+namespace Packets {
+    // packets from the server to clients
+    enum ServerPacket { S_CHAT, S_WORLD_SEGMENT, S_ENTITY_UPDATE };
+    // packets from clients to the server
+    enum ClientPacket { C_CHAT, C_CONTROLLER };
+
+    template<int N>
+    void writeVector(OutPacket& out, const Vector<N>& v) {
+        for(int i = 0; i < N; i++) {
+            out.writeFloat(v[i]);
+        }
+    }
+
+    template<int N>
+    bool readVector(InPacket& in, Vector<N>& v) {
+        for(int i = 0; i < N; i++) {
+            if(in.readFloat(v[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
 
 #endif

+ 26 - 0
common/network/toclient/EntityUpdatePacket.cpp

@@ -0,0 +1,26 @@
+#include "common/network/toclient/EntityUpdatePacket.h"
+#include "common/network/Packets.h"
+
+EntityUpdatePacket::EntityUpdatePacket(const Entity& e)
+    : lengthAngle(e.lengthAngle), widthAngle(e.widthAngle),
+      position(e.position) {
+}
+
+EntityUpdatePacket::EntityUpdatePacket() {
+}
+
+void EntityUpdatePacket::write(OutPacket& out) const {
+    out.writeU16(Packets::S_ENTITY_UPDATE);
+    out.writeFloat(lengthAngle);
+    out.writeFloat(widthAngle);
+    Packets::writeVector(out, position);
+}
+
+bool EntityUpdatePacket::read(InPacket& in) {
+    return in.readFloat(lengthAngle) || in.readFloat(widthAngle) ||
+           Packets::readVector(in, position);
+}
+
+int EntityUpdatePacket::getSize() {
+    return sizeof(EntityUpdatePacket) + 2;
+}

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

@@ -0,0 +1,22 @@
+#ifndef ENTITY_UPDATE_PACKET_H
+#define ENTITY_UPDATE_PACKET_H
+
+#include "common/entities/Entity.h"
+#include "math/Vector.h"
+#include "network/Packet.h"
+
+struct EntityUpdatePacket {
+    float lengthAngle;
+    float widthAngle;
+    Vector3 position;
+
+    EntityUpdatePacket(const Entity& e);
+    EntityUpdatePacket();
+
+    void write(OutPacket& out) const;
+    bool read(InPacket& in);
+
+    static int getSize();
+};
+
+#endif

+ 26 - 0
common/network/toserver/ControllerPacket.cpp

@@ -0,0 +1,26 @@
+#include "common/network/toserver/ControllerPacket.h"
+#include "common/network/Packets.h"
+
+ControllerPacket::ControllerPacket() : flags(0) {
+}
+
+void ControllerPacket::set(Type type) {
+    flags |= (1 << type);
+}
+
+bool ControllerPacket::has(Type type) const {
+    return flags & (1 << type);
+}
+
+void ControllerPacket::write(OutPacket& out) const {
+    out.writeU16(Packets::C_CONTROLLER);
+    out.writeU32(flags);
+}
+
+bool ControllerPacket::read(InPacket& in) {
+    return in.readU32(flags);
+}
+
+int ControllerPacket::getSize() {
+    return sizeof(ControllerPacket) + 2;
+}

+ 32 - 0
common/network/toserver/ControllerPacket.h

@@ -0,0 +1,32 @@
+#ifndef CONTROLLER_PACKET_H
+#define CONTROLLER_PACKET_H
+
+#include "network/Packet.h"
+
+class ControllerPacket {
+    uint32 flags;
+
+public:
+    enum Type {
+        LEFT,
+        RIGHT,
+        UP,
+        DOWN,
+        JUMP,
+        SNEAK,
+        CAM_LEFT,
+        CAM_RIGHT,
+        CAM_UP,
+        CAM_DOWN
+    };
+    ControllerPacket();
+
+    void set(Type type);
+    bool has(Type type) const;
+    void write(OutPacket& out) const;
+    bool read(InPacket& in);
+
+    static int getSize();
+};
+
+#endif

+ 22 - 8
common/world/World.cpp

@@ -2,6 +2,7 @@
 
 #include "common/world/HighMap.h"
 #include "common/world/World.h"
+#include "utils/Logger.h"
 #include "utils/Random.h"
 
 World::World(const BlockRegistry& blockRegistry)
@@ -24,8 +25,17 @@ int World::getHeight() const {
     return blocks.getHeight();
 }
 
-void World::addPlayer(Player* p) {
-    players.add(p);
+void World::addEntity(Entity* e) {
+    entities.add(e);
+}
+
+void World::removeEntity(Entity* e) {
+    for(int i = 0; i < entities.getLength(); i++) {
+        if(entities[i] == e) {
+            entities.removeBySwap(i);
+            return;
+        }
+    }
 }
 
 List<CollisionBox> World::getBoxes(const CollisionBox& box) const {
@@ -50,14 +60,18 @@ List<CollisionBox> World::getBoxes(const CollisionBox& box) const {
 }
 
 void World::tick() {
-    for(Player* p : players) {
-        p->tick();
+    for(Entity* e : entities) {
+        e->tick();
+        if(e->skip) {
+            LOG_DEBUG("skip");
+            continue;
+        }
 
-        Vector3 move = p->getVelocity();
-        CollisionBox box = p->getCollisionBox();
+        Vector3 move = e->getVelocity();
+        CollisionBox box = e->getCollisionBox();
         List<CollisionBox> boxes = getBoxes(box.expand(move));
         if(boxes.getLength() == 0) {
-            p->move(move);
+            e->move(move);
             continue;
         }
         Vector3 realMove;
@@ -124,6 +138,6 @@ void World::tick() {
                 }
             }
         }
-        p->move(realMove);
+        e->move(realMove);
     }
 }

+ 4 - 3
common/world/World.h

@@ -2,14 +2,14 @@
 #define WORLD_H
 
 #include "common/block/BlockRegistry.h"
-#include "common/entities/Player.h"
+#include "common/entities/Entity.h"
 #include "common/world/BlockStorage.h"
 #include "utils/List.h"
 
 class World final {
     const BlockRegistry& blockRegistry;
     BlockStorage blocks;
-    List<Player*> players;
+    List<Entity*> entities;
 
 public:
     mutable bool dirty;
@@ -22,7 +22,8 @@ public:
     int getSize() const;
     int getHeight() const;
 
-    void addPlayer(Player* p);
+    void addEntity(Entity* e);
+    void removeEntity(Entity* e);
 
     void tick();
 

+ 3 - 1
meson.build

@@ -8,7 +8,9 @@ src_common = [
     'common/world/World.cpp', 
     'common/world/HighMap.cpp',
     'common/utils/CollisionBox.cpp',
-    'common/entities/Player.cpp',
+    'common/entities/Entity.cpp',
+    'common/network/toserver/ControllerPacket.cpp',
+    'common/network/toclient/EntityUpdatePacket.cpp',
 ]
 
 src_server = ['server/Main.cpp',

+ 19 - 11
server/Game.cpp

@@ -1,7 +1,9 @@
 #include "server/Game.h"
 #include "commands/Commands.h"
+#include "common/network/toclient/EntityUpdatePacket.h"
 #include "memory/UniquePointer.h"
 #include "raw-terminal/RawReader.h"
+#include "server/GameServer.h"
 #include "server/packets/WorldPackets.h"
 #include "server/world/WorldGenerator.h"
 #include "utils/List.h"
@@ -9,10 +11,11 @@
 
 static bool running = true;
 static RawReader<256, 10> reader{0, "> "};
-static List<UniquePointer<World>> worlds;
 
 Clock Game::ticksPerSecond;
 BlockRegistry Game::blocks;
+World Game::world{blocks};
+static Entity* test = nullptr;
 
 void Game::stop() {
     running = false;
@@ -22,14 +25,8 @@ bool Game::isRunning() {
     return running;
 }
 
-void Game::testWorld() {
-    worlds.add(new World(blocks));
-    WorldGenerator wg(blocks, *(worlds[0]));
-    wg.generate();
-}
-
-World& Game::getTestWorld() {
-    return *(worlds[0]);
+void Game::init() {
+    WorldGenerator::generate(world);
 }
 
 static void handleCommands() {
@@ -46,6 +43,13 @@ static void handleCommands() {
 
 void Game::tick() {
     ticksPerSecond.update();
+    world.tick();
+    if(test != nullptr) {
+        EntityUpdatePacket e(*test);
+        OutPacket out = OutPacket::sequenced(EntityUpdatePacket::getSize());
+        e.write(out);
+        GameServer::sendToAll(out);
+    }
     handleCommands();
 }
 
@@ -53,12 +57,16 @@ void Game::addPlayer(ServerPlayer& p) {
     LOG_INFO("player add");
     for(int x = -1; x <= 1; x++) {
         for(int z = -1; z <= 1; z++) {
-            WorldPackets::sendChunk(p, getTestWorld(), x, z);
+            WorldPackets::sendChunk(p, world, x, z);
         }
     }
+    p.setPosition(Vector3(0.0f, 2.0f, 0.0f));
+    test = &p;
+    world.addEntity(&p);
 }
 
 void Game::removePlayer(ServerPlayer& p) {
     LOG_INFO("player remove");
-    (void)p;
+    test = nullptr;
+    world.removeEntity(&p);
 }

+ 2 - 2
server/Game.h

@@ -8,12 +8,12 @@
 namespace Game {
     extern Clock ticksPerSecond;
     extern BlockRegistry blocks;
+    extern World world;
 
     void stop();
     bool isRunning();
 
-    void testWorld();
-    World& getTestWorld();
+    void init();
     void tick();
 
     void addPlayer(ServerPlayer& p);

+ 8 - 1
server/GameServer.cpp

@@ -7,6 +7,12 @@
 static Server server;
 static HashMap<int, UniquePointer<ServerPlayer>> players;
 
+static void handleControllerPacket(ServerPlayer& p, InPacket& in) {
+    ControllerPacket cp;
+    cp.read(in);
+    p.onControllerPacket(cp);
+}
+
 struct Receiver {
     void onConnect(Server::Client& client) {
         if(players.tryEmplace(client.getId(), new ServerPlayer(client))) {
@@ -45,7 +51,8 @@ struct Receiver {
             return;
         }
         switch(id) {
-            case C_CHAT: (*p)->onChat(in); break;
+            case Packets::C_CHAT: (*p)->onChat(in); break;
+            case Packets::C_CONTROLLER: handleControllerPacket(**p, in); break;
             default: LOG_WARNING("invalid packet from client");
         }
     }

+ 2 - 2
server/Main.cpp

@@ -11,8 +11,8 @@ void loop() {
         lag += clock.update();
         while(lag >= NANOS_PER_TICK) {
             lag -= NANOS_PER_TICK;
-            GameServer::tick();
             Game::tick();
+            GameServer::tick();
         }
         Clock::Nanos waitNanos = NANOS_PER_TICK - lag;
         if(waitNanos > 300000) {
@@ -27,7 +27,7 @@ int main() {
     if(GameServer::init(11196, 50)) {
         return 0;
     }
-    Game::testWorld();
+    Game::init();
     loop();
     return 0;
 }

+ 1 - 1
server/commands/DefaultCommands.cpp

@@ -15,7 +15,7 @@ static void commandSay(const Commands::Arguments& args) {
         s.append(' ');
     }
     OutPacket out = OutPacket::reliable(260);
-    out.writeU16(S_CHAT);
+    out.writeU16(Packets::S_CHAT);
     out.writeString(s);
     GameServer::sendToAll(out);
     puts(s);

+ 57 - 0
server/entities/ServerPlayer.cpp

@@ -1,12 +1,69 @@
 #include "server/entities/ServerPlayer.h"
+#include "utils/Logger.h"
 
 ServerPlayer::ServerPlayer(Server::Client& client) : client(client) {
 }
 
+void ServerPlayer::tick() {
+    if(!history.canRead()) {
+        skip = true;
+        return;
+    }
+    skip = false;
+    Entity::tick();
+
+    ControllerPacket cp = history.read();
+
+    Quaternion q = getRotation();
+    Vector3 up(0.0f, 1.0f, 0.0f);
+    Vector3 back = q * Vector3(0.0f, 0.0f, -1.0f);
+    back[1] = 0.0f;
+    back.normalize();
+    Vector3 right = back.cross(up);
+
+    constexpr float speed = 0.1f;
+    if(cp.has(ControllerPacket::Type::DOWN)) {
+        addForce(back * speed);
+    }
+    if(cp.has(ControllerPacket::Type::UP)) {
+        addForce(back * -speed);
+    }
+    if(cp.has(ControllerPacket::Type::LEFT)) {
+        addForce(right * -speed);
+    }
+    if(cp.has(ControllerPacket::Type::RIGHT)) {
+        addForce(right * speed);
+    }
+    if(cp.has(ControllerPacket::Type::JUMP) && isOnGround()) {
+        addForce(up * 0.5f);
+    }
+    if(cp.has(ControllerPacket::Type::SNEAK)) {
+        addForce(up * -speed);
+    }
+
+    constexpr float rotationSpeed = 4.0f;
+    if(cp.has(ControllerPacket::Type::CAM_LEFT)) {
+        addLengthAngle(-rotationSpeed);
+    }
+    if(cp.has(ControllerPacket::Type::CAM_RIGHT)) {
+        addLengthAngle(rotationSpeed);
+    }
+    if(cp.has(ControllerPacket::Type::CAM_UP)) {
+        addWidthAngle(-rotationSpeed * 0.5f);
+    }
+    if(cp.has(ControllerPacket::Type::CAM_DOWN)) {
+        addWidthAngle(rotationSpeed * 0.5f);
+    }
+}
+
 void ServerPlayer::onChat(InPacket& in) {
     (void)in;
 }
 
 void ServerPlayer::send(OutPacket& out) {
     client.send(out);
+}
+
+void ServerPlayer::onControllerPacket(const ControllerPacket& cp) {
+    history.write(cp);
 }

+ 7 - 2
server/entities/ServerPlayer.h

@@ -1,18 +1,23 @@
 #ifndef SERVER_PLAYER_H
 #define SERVER_PLAYER_H
 
-#include "common/entities/Player.h"
+#include "common/entities/Entity.h"
+#include "common/network/toserver/ControllerPacket.h"
 #include "network/Server.h"
+#include "utils/RingBuffer.h"
 
-class ServerPlayer : public Player {
+class ServerPlayer : public Entity {
     Server::Client& client;
+    RingBuffer<ControllerPacket, 30> history;
 
 public:
     ServerPlayer(Server::Client& client);
 
+    void tick() override;
     void onChat(InPacket& in);
     void sendChunk();
     void send(OutPacket& out);
+    void onControllerPacket(const ControllerPacket& cp);
 };
 
 #endif

+ 1 - 1
server/packets/WorldPackets.cpp

@@ -7,7 +7,7 @@ void WorldPackets::sendChunk(ServerPlayer& p, World& w, int cx, int cz) {
     cz *= size;
     OutPacket out = OutPacket::reliable(
         w.getHeight() * size * size * sizeof(BlockId) * 2 + 10);
-    out.writeU16(S_WORLD_SEGMENT);
+    out.writeU16(Packets::S_WORLD_SEGMENT);
     out.writeS32(cx);
     out.writeS32(cz);
     int endX = cx + size;

+ 7 - 10
server/world/WorldGenerator.cpp

@@ -1,18 +1,15 @@
 #include "server/world/WorldGenerator.h"
 #include "common/world/HighMap.h"
+#include "server/Game.h"
 
-WorldGenerator::WorldGenerator(const BlockRegistry& blocks, World& world)
-    : blocks(blocks), world(world) {
-}
-
-void WorldGenerator::generate() {
-    const Block& stone = blocks.getBlock("stone");
-    HighMap map(world.getSize(), world.getHeight());
-    for(int x = 0; x < world.getSize(); x++) {
-        for(int z = 0; z < world.getSize(); z++) {
+void WorldGenerator::generate(World& w) {
+    const Block& stone = Game::blocks.getBlock("stone");
+    HighMap map(w.getSize(), w.getHeight());
+    for(int x = 0; x < w.getSize(); x++) {
+        for(int z = 0; z < w.getSize(); z++) {
             int height = map.getHeight(x, z);
             for(int y = 0; y < height; y++) {
-                world.setBlock(x, y, z, stone);
+                w.setBlock(x, y, z, stone);
             }
         }
     }

+ 3 - 8
server/world/WorldGenerator.h

@@ -3,13 +3,8 @@
 
 #include "common/world/World.h"
 
-class WorldGenerator final {
-    const BlockRegistry& blocks;
-    World& world;
-
-public:
-    WorldGenerator(const BlockRegistry& blocks, World& world);
-    void generate();
-};
+namespace WorldGenerator {
+    void generate(World& world);
+}
 
 #endif

+ 1 - 1
subprojects/gaming-core

@@ -1 +1 @@
-Subproject commit d965a3542acbce525e4372258c1e5b1ef61bdc63
+Subproject commit eb3c259056e17f8772986c786343ca563123c81e