]> git.localhorst.tv Git - blank.git/commitdiff
treat head pitch and yaw as entity state
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 22 Oct 2015 07:25:41 +0000 (09:25 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 22 Oct 2015 07:25:41 +0000 (09:25 +0200)
16 files changed:
doc/protocol
src/app/app.cpp
src/client/net.cpp
src/io/WorldSave.cpp
src/model/Instance.hpp
src/model/Model.hpp
src/model/model.cpp
src/net/Packet.hpp
src/net/net.cpp
src/server/net.cpp
src/ui/PlayerController.hpp
src/ui/ui.cpp
src/world/Entity.hpp
src/world/EntityState.hpp
src/world/world.cpp
tst/net/PacketTest.cpp

index ce3f5fd75afcd4515d351f6d396ab1a3c5679ce8..025a13d1b09e784d291ea0398e1503be9ffc312e 100644 (file)
@@ -31,11 +31,12 @@ packu          2    16bit unsigned  int representing a float value normalized to
 vec3n          6    3x packn
 vec3u          6    3x packu
 quat           8    4x packn float
-entity state  50    [ 0] vec3i chunk pos (there's a variation where this is a vec3b)
+entity state  42    [ 0] vec3i chunk pos (there's a variation where this is a vec3b)
                     [12] vec3u block pos by 16,
                     [18] vec3 velocity,
                     [30] quat orientation,
-                    [38] 12 reserved bytes (used to be angular velocity)
+                    [38] packn pitch by PI/2
+                                       [40] packn yaw by PI
 
 
 Packets
@@ -77,9 +78,9 @@ Code: 2
 Payload:
         0 entity ID of the player, 32bit unsigned int
         4 entity state of the player
-       54 name of the world the server's currently running
+       46 name of the world the server's currently running
           max 32 byte UTF-8 string
-Length: 54-86
+Length: 47-78
 
 
 Part
@@ -102,12 +103,10 @@ Sent by clients to notify the server of their changes to the player.
 Code: 4
 Payload:
         0 player's entity state as predicted by the client
-       50 movement input, vec3n
-       56 pitch input by PI/2, packn
-       58 yaw input by PI, packn
-       60 active actions, 8bit bit field, first three bits are primary, secondary, and tertiary
-       61 selected inventory slot, 8bit unsigned int
-Length: 62
+       42 movement input, vec3n
+       48 active actions, 8bit bit field, first three bits are primary, secondary, and tertiary
+       49 selected inventory slot, 8bit unsigned int
+Length: 50
 
 
 Spawn Entity
@@ -120,11 +119,11 @@ Payload:
         0 entity ID, 32bit unsigned int
         4 entity's model ID, 32bit unsigned int
         8 entity state
-       58 bounding box of the entity, 6x 32bit float
-       82 flags, 32bit bitfield with boolean values
+       50 bounding box of the entity, 6x 32bit float
+       74 flags, 32bit bitfield with boolean values
           1: world collision
-       86 entity name, max 32 byte UTF-8 string
-Length: 87 - 118
+       78 entity name, max 32 byte UTF-8 string
+Length: 79 - 110
 
 
 Despawn Entity
@@ -146,12 +145,12 @@ Contained entities must be ordered by ascending entity ID.
 
 Code: 7
 Payload:
-        0 number of entities, 32bit int, 1-10
+        0 number of entities, 32bit int, 1-12
         4 base for chunk coordinates, vec3i
        16 entity ID, 32bit unsigned int
        20 entity state with vec3b as chunk position (rather than vec3i)
-       62 next entity...
-Length: 16 + multiple of 45, max 466
+       53 next entity...
+Length: 16 + multiple of 37, max 460
 
 
 Player Correction
@@ -163,7 +162,7 @@ Code: 8
 Payload:
         0 sequence number of the offending packet, 16bit unsigned int
         2 entity state of the player's entity on the server
-Length: 52
+Length: 44
 
 
 Chunk Begin
index aba7093186853ba04a29fa64d1402506d1894cb3..35a3e3e8d37ada79dc8327160adfe1b4072838fa 100644 (file)
@@ -528,6 +528,8 @@ void AssetLoader::LoadModels(
                        in.Skip(Token::EQUALS);
                        if (prop_name == "root") {
                                model.RootPart().Read(in, tex_index, shapes);
+                       } else if (prop_name == "body") {
+                               model.SetBody(in.GetULong());
                        } else if (prop_name == "eyes") {
                                model.SetEyes(in.GetULong());
                        } else {
index 36d598bd9b2ba76681c509483a052f22717d6a6b..f0a9eee6af31c04608670c8cfae0d3ef960e3800 100644 (file)
@@ -294,8 +294,6 @@ uint16_t Client::SendPlayerUpdate(
        auto pack = Packet::Make<Packet::PlayerUpdate>(client_pack);
        pack.WritePredictedState(prediction);
        pack.WriteMovement(movement);
-       pack.WritePitch(pitch);
-       pack.WriteYaw(yaw);
        pack.WriteActions(actions);
        pack.WriteSlot(slot);
        return conn.Send(client_pack, client_sock);
index 6414dd0a7be43129f2840562454ead38ae12bc79..86532787653d1b24deef8baec749501eab3377ff 100644 (file)
@@ -130,6 +130,10 @@ void WorldSave::Read(Player &player) const {
                        in.ReadVec(state.block_pos);
                } else if (name == "orientation") {
                        in.ReadQuat(state.orient);
+               } else if (name == "pitch") {
+                       state.pitch = in.GetFloat();
+               } else if (name == "yaw") {
+                       state.yaw = in.GetFloat();
                } else if (name == "slot") {
                        int slot;
                        in.ReadNumber(slot);
@@ -151,6 +155,8 @@ void WorldSave::Write(const Player &player) const {
        out << "chunk = " << state.chunk_pos << ';' << endl;
        out << "position = " << state.block_pos << ';' << endl;
        out << "orientation = " << state.orient << ';' << endl;
+       out << "pitch = " << state.pitch << ';' << endl;
+       out << "yaw = " << state.yaw << ';' << endl;
        out << "slot = " << player.GetInventorySlot() << ';' << endl;
 }
 
index 0c828393675cb50f6e175510cfacfd6592a083be..80c8f710fd14e7a0f60988a2fc6b0b73122a1110 100644 (file)
@@ -26,6 +26,9 @@ public:
        operator bool() const noexcept { return model; }
        const Model &GetModel() const noexcept { return *model; }
 
+       glm::mat4 BodyTransform() const noexcept;
+       Part::State &BodyState() noexcept;
+
        glm::mat4 EyesTransform() const noexcept;
        Part::State &EyesState() noexcept;
 
index ad8cb04a4ffbb1878150cedac1c2cbca493cb498..145a6d9c0fd56cf40dc29145360e2d577a899b26 100644 (file)
@@ -31,6 +31,9 @@ public:
        Part &GetPart(std::size_t i) noexcept { return *part[i]; }
        const Part &GetPart(std::size_t i) const noexcept { return *part[i]; }
 
+       void SetBody(std::uint16_t id) { body_id = id; }
+       const Part &GetBodyPart() const noexcept { return GetPart(body_id); }
+
        void SetEyes(std::uint16_t id) { eyes_id = id; }
        const Part &GetEyesPart() const noexcept { return GetPart(eyes_id); }
 
@@ -41,6 +44,7 @@ private:
        std::uint32_t id;
        Part root;
        std::vector<Part *> part;
+       std::uint16_t body_id;
        std::uint16_t eyes_id;
 
 };
index cad62ac2ec0cea30c99e39685adbef0729b6f3a8..db44cbf21c0e351c757dcb484027c93dedd81672 100644 (file)
@@ -27,6 +27,14 @@ Instance::~Instance() {
 
 }
 
+Part::State &Instance::BodyState() noexcept {
+       return state[model->GetBodyPart().ID()];
+}
+
+glm::mat4 Instance::BodyTransform() const noexcept {
+       return model->GetBodyPart().GlobalTransform(*this);
+}
+
 Part::State &Instance::EyesState() noexcept {
        return state[model->GetEyesPart().ID()];
 }
@@ -44,6 +52,7 @@ Model::Model()
 : id(0)
 , root()
 , part()
+, body_id(0)
 , eyes_id(0) {
 
 }
index a6a9d54c478894e02129c893d5ff57ad2d1be0de..97b76c8a3416b5b83f0cfd83015a506e5becfdf4 100644 (file)
@@ -112,7 +112,7 @@ struct Packet {
 
        struct Join : public Payload {
                static constexpr std::uint8_t TYPE = 2;
-               static constexpr std::size_t MAX_LEN = 86;
+               static constexpr std::size_t MAX_LEN = 78;
 
                void WritePlayer(const Entity &) noexcept;
                void ReadPlayerID(std::uint32_t &) const noexcept;
@@ -128,16 +128,12 @@ struct Packet {
 
        struct PlayerUpdate : public Payload {
                static constexpr std::uint8_t TYPE = 4;
-               static constexpr std::size_t MAX_LEN = 62;
+               static constexpr std::size_t MAX_LEN = 50;
 
                void WritePredictedState(const EntityState &) noexcept;
                void ReadPredictedState(EntityState &) const noexcept;
                void WriteMovement(const glm::vec3 &) noexcept;
                void ReadMovement(glm::vec3 &) const noexcept;
-               void WritePitch(float) noexcept;
-               void ReadPitch(float &) const noexcept;
-               void WriteYaw(float) noexcept;
-               void ReadYaw(float &) const noexcept;
                void WriteActions(std::uint8_t) noexcept;
                void ReadActions(std::uint8_t &) const noexcept;
                void WriteSlot(std::uint8_t) noexcept;
@@ -146,7 +142,7 @@ struct Packet {
 
        struct SpawnEntity : public Payload {
                static constexpr std::uint8_t TYPE = 5;
-               static constexpr std::size_t MAX_LEN = 118;
+               static constexpr std::size_t MAX_LEN = 110;
 
                void WriteEntity(const Entity &) noexcept;
                void ReadEntityID(std::uint32_t &) const noexcept;
@@ -164,11 +160,11 @@ struct Packet {
 
        struct EntityUpdate : public Payload {
                static constexpr std::uint8_t TYPE = 7;
-               static constexpr std::size_t MAX_LEN = 466;
+               static constexpr std::size_t MAX_LEN = 460;
 
-               static constexpr std::uint32_t MAX_ENTITIES = 10;
+               static constexpr std::uint32_t MAX_ENTITIES = 12;
                static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
-                       return 16 + (num * 45);
+                       return 16 + (num * 37);
                }
 
                void WriteEntityCount(std::uint32_t) noexcept;
@@ -183,7 +179,7 @@ struct Packet {
 
        struct PlayerCorrection : public Payload {
                static constexpr std::uint8_t TYPE = 8;
-               static constexpr std::size_t MAX_LEN = 52;
+               static constexpr std::size_t MAX_LEN = 44;
 
                void WritePacketSeq(std::uint16_t) noexcept;
                void ReadPacketSeq(std::uint16_t &) const noexcept;
index 25e5b43e7bd2ef732dcd4da97d22524a087faf1c..9b50479b135445ae0225a28f98653fee18c6f000 100644 (file)
@@ -281,6 +281,8 @@ void Packet::Payload::Write(const EntityState &state, size_t off) noexcept {
        WritePackU(state.block_pos * (1.0f / 16.0f), off + 12);
        Write(state.velocity, off + 18);
        Write(state.orient, off + 30);
+       WritePackN(state.pitch * PI_0p5_inv, off + 38);
+       WritePackN(state.yaw * PI_inv, off + 40);
 }
 
 void Packet::Payload::Read(EntityState &state, size_t off) const noexcept {
@@ -288,7 +290,11 @@ void Packet::Payload::Read(EntityState &state, size_t off) const noexcept {
        ReadPackU(state.block_pos, off + 12);
        Read(state.velocity, off + 18);
        Read(state.orient, off + 30);
+       ReadPackN(state.pitch, off + 38);
+       ReadPackN(state.yaw, off + 40);
        state.block_pos *= 16.0f;
+       state.pitch *= PI_0p5;
+       state.yaw *= PI;
 }
 
 void Packet::Payload::Write(const EntityState &state, const glm::ivec3 &base, size_t off) noexcept {
@@ -296,6 +302,8 @@ void Packet::Payload::Write(const EntityState &state, const glm::ivec3 &base, si
        WritePackU(state.block_pos * (1.0f / 16.0f), off + 3);
        Write(state.velocity, off + 9);
        Write(state.orient, off + 21);
+       WritePackN(state.pitch * PI_0p5_inv, off + 29);
+       WritePackN(state.yaw * PI_inv, off + 31);
 }
 
 void Packet::Payload::Read(EntityState &state, const glm::ivec3 &base, size_t off) const noexcept {
@@ -303,13 +311,12 @@ void Packet::Payload::Read(EntityState &state, const glm::ivec3 &base, size_t of
        ReadPackU(state.block_pos, off + 3);
        Read(state.velocity, off + 9);
        Read(state.orient, off + 21);
+       ReadPackN(state.pitch, off + 29);
+       ReadPackN(state.yaw, off + 31);
        state.chunk_pos += base;
        state.block_pos *= 16.0f;
-}
-
-void Packet::Payload::WritePackN(float val, size_t off) noexcept {
-       int16_t raw = glm::clamp(glm::round(val * 32767.0f), -32767.0f, 32767.0f);
-       Write(raw, off);
+       state.pitch *= PI_0p5;
+       state.yaw *= PI;
 }
 
 void Packet::Payload::WritePackB(const glm::ivec3 &val, size_t off) noexcept {
@@ -328,6 +335,11 @@ void Packet::Payload::ReadPackB(glm::ivec3 &val, size_t off) const noexcept {
        val.z = conv;
 }
 
+void Packet::Payload::WritePackN(float val, size_t off) noexcept {
+       int16_t raw = glm::clamp(glm::round(val * 32767.0f), -32767.0f, 32767.0f);
+       Write(raw, off);
+}
+
 void Packet::Payload::ReadPackN(float &val, size_t off) const noexcept {
        int16_t raw = 0;
        Read(raw, off);
@@ -392,11 +404,11 @@ void Packet::Join::ReadPlayerState(EntityState &state) const noexcept {
 }
 
 void Packet::Join::WriteWorldName(const string &name) noexcept {
-       WriteString(name, 54, 32);
+       WriteString(name, 46, 32);
 }
 
 void Packet::Join::ReadWorldName(string &name) const noexcept {
-       ReadString(name, 54, 32);
+       ReadString(name, 46, 32);
 }
 
 void Packet::PlayerUpdate::WritePredictedState(const EntityState &state) noexcept {
@@ -408,47 +420,27 @@ void Packet::PlayerUpdate::ReadPredictedState(EntityState &state) const noexcept
 }
 
 void Packet::PlayerUpdate::WriteMovement(const glm::vec3 &mov) noexcept {
-       WritePackN(mov, 50);
+       WritePackN(mov, 42);
 }
 
 void Packet::PlayerUpdate::ReadMovement(glm::vec3 &mov) const noexcept {
-       ReadPackN(mov, 50);
-}
-
-void Packet::PlayerUpdate::WritePitch(float pitch) noexcept {
-       float conv = pitch * PI_0p5_inv;
-       WritePackN(conv, 56);
-}
-
-void Packet::PlayerUpdate::ReadPitch(float &pitch) const noexcept {
-       ReadPackN(pitch, 56);
-       pitch *= PI_0p5;
-}
-
-void Packet::PlayerUpdate::WriteYaw(float yaw) noexcept {
-       float conv = yaw * PI_inv;
-       WritePackN(conv, 58);
-}
-
-void Packet::PlayerUpdate::ReadYaw(float &yaw) const noexcept {
-       ReadPackN(yaw, 58);
-       yaw *= PI;
+       ReadPackN(mov, 42);
 }
 
 void Packet::PlayerUpdate::WriteActions(uint8_t actions) noexcept {
-       Write(actions, 60);
+       Write(actions, 48);
 }
 
 void Packet::PlayerUpdate::ReadActions(uint8_t &actions) const noexcept {
-       Read(actions, 60);
+       Read(actions, 48);
 }
 
 void Packet::PlayerUpdate::WriteSlot(uint8_t slot) noexcept {
-       Write(slot, 61);
+       Write(slot, 49);
 }
 
 void Packet::PlayerUpdate::ReadSlot(uint8_t &slot) const noexcept {
-       Read(slot, 61);
+       Read(slot, 49);
 }
 
 void Packet::SpawnEntity::WriteEntity(const Entity &e) noexcept {
@@ -459,13 +451,13 @@ void Packet::SpawnEntity::WriteEntity(const Entity &e) noexcept {
                Write(uint32_t(0), 4);
        }
        Write(e.GetState(), 8);
-       Write(e.Bounds(), 58);
+       Write(e.Bounds(), 50);
        uint32_t flags = 0;
        if (e.WorldCollidable()) {
                flags |= 1;
        }
-       Write(flags, 82);
-       WriteString(e.Name(), 86, 32);
+       Write(flags, 74);
+       WriteString(e.Name(), 78, 32);
 }
 
 void Packet::SpawnEntity::ReadEntityID(uint32_t &id) const noexcept {
@@ -483,9 +475,9 @@ void Packet::SpawnEntity::ReadEntity(Entity &e) const noexcept {
        string name;
 
        Read(state, 8);
-       Read(bounds, 58);
-       Read(flags, 82);
-       ReadString(name, 86, 32);
+       Read(bounds, 50);
+       Read(flags, 74);
+       ReadString(name, 78, 32);
 
        e.SetState(state);
        e.Bounds(bounds);
index b681eec3f74c5d1f3ea576c48d9a2e7138073c7e..cdd1a0a6092c47d9e9dab5b83f1474245c74ac3a 100644 (file)
@@ -550,21 +550,17 @@ void ClientConnection::On(const Packet::PlayerUpdate &pack) {
                return;
        }
        glm::vec3 movement(0.0f);
-       float pitch = 0.0f;
-       float yaw = 0.0f;
        uint8_t new_actions;
        uint8_t slot;
 
        player_update_pack = pack.Seq();
        pack.ReadPredictedState(player_update_state);
        pack.ReadMovement(movement);
-       pack.ReadPitch(pitch);
-       pack.ReadYaw(yaw);
        pack.ReadActions(new_actions);
        pack.ReadSlot(slot);
 
        input->SetMovement(movement);
-       input->TurnHead(pitch - input->GetPitch(), yaw - input->GetYaw());
+       input->TurnHead(player_update_state.pitch - input->GetPitch(), player_update_state.yaw - input->GetYaw());
        input->SelectInventory(slot);
 
        if ((new_actions & 0x01) && !(old_actions & 0x01)) {
index 9b4057b380d02c7a20582763103dc877580857fe..b9d3b2bd6cf6854f53cf5586b07fa49dcc72cc12 100644 (file)
@@ -35,9 +35,9 @@ public:
        void TurnHead(float pitch, float yaw) noexcept;
 
        /// get player pitch in radians, normalized to [-PI/2,PI/2]
-       float GetPitch() const noexcept { return pitch; }
+       float GetPitch() const noexcept;
        /// get player yaw in radians, normalized to [-PI,PI]
-       float GetYaw() const noexcept { return yaw; }
+       float GetYaw() const noexcept;
 
        /// start doing primary action
        /// what exactly this means depends on the active item
@@ -62,8 +62,6 @@ private:
        World &world;
        Player &player;
        glm::vec3 move_dir;
-       float pitch;
-       float yaw;
        bool dirty;
 
        WorldCollision aim_world;
index 0f82139b2a7bd5350db9965e51d89ea1ea3c0843..048aed1ac81559e21e2eee740d90a195bf5df22b 100644 (file)
@@ -37,8 +37,6 @@ PlayerController::PlayerController(World &world, Player &player)
 : world(world)
 , player(player)
 , move_dir(0.0f)
-, pitch(0.0f)
-, yaw(0.0f)
 , dirty(true)
 , aim_world()
 , aim_entity() {
@@ -55,19 +53,15 @@ void PlayerController::SetMovement(const glm::vec3 &m) noexcept {
 }
 
 void PlayerController::TurnHead(float dp, float dy) noexcept {
-       pitch += dp;
-       if (pitch > PI / 2) {
-               pitch = PI / 2;
-       } else if (pitch < -PI / 2) {
-               pitch = -PI / 2;
-       }
-       yaw += dy;
-       if (yaw > PI) {
-               yaw -= PI * 2;
-       } else if (yaw < -PI) {
-               yaw += PI * 2;
-       }
-       Invalidate();
+       player.GetEntity().TurnHead(dp, dy);
+}
+
+float PlayerController::GetPitch() const noexcept {
+       return player.GetEntity().Pitch();
+}
+
+float PlayerController::GetYaw() const noexcept {
+       return player.GetEntity().Yaw();
 }
 
 void PlayerController::SelectInventory(int i) noexcept {
@@ -85,9 +79,7 @@ void PlayerController::Invalidate() noexcept {
 void PlayerController::UpdatePlayer() noexcept {
        constexpr float max_vel = 5.0f; // in m/s
        if (dirty) {
-               player.GetEntity().Orientation(glm::quat(glm::vec3(0.0f, yaw, 0.0f)));
-               player.GetEntity().GetModel().EyesState().orientation = glm::quat(glm::vec3(pitch, 0.0f, 0.0f));
-               player.GetEntity().TargetVelocity(glm::rotateY(move_dir * max_vel, yaw));
+               player.GetEntity().TargetVelocity(glm::rotateY(move_dir * max_vel, player.GetEntity().Yaw()));
 
                Ray aim = player.Aim();
                if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) {
index 65e1441aa6b1407f40a50423fd7ffce2548e0514..4f0d3c435f58e709a4c33dba335453f03b75d81b 100644 (file)
@@ -37,6 +37,7 @@ public:
        bool WorldCollidable() const noexcept { return world_collision; }
        void WorldCollidable(bool b) noexcept { world_collision = b; }
 
+       /// desired velocity in local coordinate system
        const glm::vec3 &TargetVelocity() const noexcept { return tgt_vel; }
        void TargetVelocity(const glm::vec3 &v) noexcept { tgt_vel = v; }
 
@@ -56,9 +57,16 @@ public:
                return state.Diff(other.state);
        }
 
+       /// orientation of local coordinate system
        const glm::quat &Orientation() const noexcept { return state.orient; }
        void Orientation(const glm::quat &o) noexcept { state.orient = o; }
 
+       /// orientation of head within local coordinate system, in radians
+       float Pitch() const noexcept { return state.pitch; }
+       float Yaw() const noexcept { return state.yaw; }
+       void TurnHead(float delta_pitch, float delta_yaw) noexcept;
+       void SetHead(float pitch, float yaw) noexcept;
+
        /// get a transform for this entity's coordinate space
        glm::mat4 Transform(const glm::ivec3 &reference) const noexcept;
        /// get a transform for this entity's view space
@@ -81,6 +89,9 @@ public:
                if (model) model.Render(M, prog);
        }
 
+private:
+       void UpdateModel() noexcept;
+
 private:
        Instance model;
 
index d3e34e55c644e48c5cf11f0c032ffa9e29fd52cb..21b60dd0de105ee27a9b25ece204896f3c89d2dd 100644 (file)
@@ -16,11 +16,15 @@ struct EntityState {
        glm::vec3 velocity;
 
        glm::quat orient;
+       float pitch;
+       float yaw;
 
        EntityState();
 
        /// make sure block_pos is within chunk bounds
        void AdjustPosition() noexcept;
+       /// make sure pitch and yaw are normalized
+       void AdjustHeading() noexcept;
 
        /// get a position vector relative to the (0,0,0) chunk
        glm::vec3 AbsolutePosition() const noexcept {
index 18853914b5536aa4427751af9270ffd59a25db17..a852038664a05410292a2e7bdd58ecfb0183f2de 100644 (file)
@@ -45,6 +45,17 @@ void Entity::Position(const glm::vec3 &pos) noexcept {
        state.AdjustPosition();
 }
 
+void Entity::TurnHead(float dp, float dy) noexcept {
+       SetHead(state.pitch + dp, state.yaw + dy);
+}
+
+void Entity::SetHead(float p, float y) noexcept {
+       state.pitch = p;
+       state.yaw = y;
+       // TODO: I feel like this could be delayed
+       UpdateModel();
+}
+
 glm::mat4 Entity::Transform(const glm::ivec3 &reference) const noexcept {
        return state.Transform(reference);
 }
@@ -66,12 +77,28 @@ Ray Entity::Aim(const Chunk::Pos &chunk_offset) const noexcept {
        return Ray{ glm::vec3(from), glm::normalize(glm::vec3(to - from)) };
 }
 
+void Entity::UpdateModel() noexcept {
+       state.AdjustHeading();
+       if (model) {
+               Part::State &body_state = model.BodyState();
+               Part::State &eyes_state = model.EyesState();
+               if (&body_state != &eyes_state) {
+                       body_state.orientation = glm::quat(glm::vec3(0.0f, state.yaw, 0.0f));
+                       eyes_state.orientation = glm::quat(glm::vec3(state.pitch, 0.0f, 0.0f));
+               } else {
+                       eyes_state.orientation = glm::quat(glm::vec3(state.pitch, state.yaw, 0.0f));
+               }
+       }
+}
+
 
 EntityState::EntityState()
 : chunk_pos(0)
 , block_pos(0.0f)
 , velocity(0.0f)
-, orient(1.0f, 0.0f, 0.0f, 0.0f) {
+, orient(1.0f, 0.0f, 0.0f, 0.0f)
+, pitch(0.0f)
+, yaw(0.0f) {
 
 }
 
@@ -102,6 +129,21 @@ void EntityState::AdjustPosition() noexcept {
        }
 }
 
+void EntityState::AdjustHeading() noexcept {
+       while (pitch > PI / 2) {
+               pitch = PI / 2;
+       }
+       while (pitch < -PI / 2) {
+               pitch = -PI / 2;
+       }
+       while (yaw > PI) {
+               yaw -= PI * 2;
+       }
+       while (yaw < -PI) {
+               yaw += PI * 2;
+       }
+}
+
 glm::mat4 EntityState::Transform(const glm::ivec3 &reference) const noexcept {
        const glm::vec3 translation = RelativePosition(reference);
        glm::mat4 transform(toMat4(orient));
@@ -165,7 +207,7 @@ Player *World::AddPlayer(const std::string &name) {
        }
        Entity &entity = AddEntity();
        entity.Name(name);
-       entity.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
+       entity.Bounds({ { -0.4f, -0.9f, -0.4f }, { 0.4f, 0.9f, 0.4f } });
        entity.WorldCollidable(true);
        ChunkIndex &index = chunks.MakeIndex(entity.ChunkCoords(), 6);
        players.emplace_back(entity, index);
@@ -183,7 +225,7 @@ Player *World::AddPlayer(const std::string &name, std::uint32_t id) {
                return nullptr;
        }
        entity->Name(name);
-       entity->Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
+       entity->Bounds({ { -0.4f, -0.9f, -0.4f }, { 0.4f, 0.9f, 0.4f } });
        entity->WorldCollidable(true);
        ChunkIndex &index = chunks.MakeIndex(entity->ChunkCoords(), 6);
        players.emplace_back(*entity, index);
index d616fd32101cecca72d2a9588c7c7a86aad351ab..27ee32c7151773b29d7b6ade1c1cbf0a3dd0cb6b 100644 (file)
@@ -108,7 +108,7 @@ void PacketTest::testLogin() {
 
 void PacketTest::testJoin() {
        auto pack = Packet::Make<Packet::Join>(udp_pack);
-       AssertPacket("Join", 2, 54, 86, pack);
+       AssertPacket("Join", 2, 47, 78, pack);
 
        Entity write_entity;
        write_entity.ID(534574);
@@ -116,6 +116,8 @@ void PacketTest::testJoin() {
        write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
        write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
        write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
+       write_entity.GetState().pitch = 0.3f;
+       write_entity.GetState().yaw = -2.3f;
        uint32_t read_id = 0;
        EntityState read_state;
        pack.WritePlayer(write_entity);
@@ -156,7 +158,7 @@ void PacketTest::testPart() {
 
 void PacketTest::testPlayerUpdate() {
        auto pack = Packet::Make<Packet::PlayerUpdate>(udp_pack);
-       AssertPacket("PlayerUpdate", 4, 62, pack);
+       AssertPacket("PlayerUpdate", 4, 50, pack);
 
        EntityState write_state;
        write_state.chunk_pos = { 7, 2, -3 };
@@ -164,27 +166,19 @@ void PacketTest::testPlayerUpdate() {
        write_state.velocity = { 0.025f, 0.001f, 0.0f };
        write_state.orient = { 1.0f, 0.0f, 0.0f, 0.0f };
        glm::vec3 write_movement(0.5f, -1.0f, 1.0f);
-       float write_pitch = 1.25f;
-       float write_yaw = -2.5f;
        uint8_t write_actions = 0x05;
        uint8_t write_slot = 3;
        pack.WritePredictedState(write_state);
        pack.WriteMovement(write_movement);
-       pack.WritePitch(write_pitch);
-       pack.WriteYaw(write_yaw);
        pack.WriteActions(write_actions);
        pack.WriteSlot(write_slot);
 
        EntityState read_state;
        glm::vec3 read_movement;
-       float read_pitch;
-       float read_yaw;
        uint8_t read_actions;
        uint8_t read_slot;
        pack.ReadPredictedState(read_state);
        pack.ReadMovement(read_movement);
-       pack.ReadPitch(read_pitch);
-       pack.ReadYaw(read_yaw);
        pack.ReadActions(read_actions);
        pack.ReadSlot(read_slot);
        AssertEqual(
@@ -195,14 +189,6 @@ void PacketTest::testPlayerUpdate() {
                "player movement input not correctly transported in PlayerUpdate packet",
                write_movement, read_movement, 0.0001f
        );
-       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
-               "player pitch input not correctly transported in PlayerUpdate packet",
-               write_pitch, read_pitch, 0.0001f
-       );
-       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
-               "player yaw input not correctly transported in PlayerUpdate packet",
-               write_yaw, read_yaw, 0.0001f
-       );
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "player actions not correctly transported in PlayerUpdate packet",
                int(write_actions), int(read_actions)
@@ -215,7 +201,7 @@ void PacketTest::testPlayerUpdate() {
 
 void PacketTest::testSpawnEntity() {
        auto pack = Packet::Make<Packet::SpawnEntity>(udp_pack);
-       AssertPacket("SpawnEntity", 5, 87, 118, pack);
+       AssertPacket("SpawnEntity", 5, 79, 110, pack);
 
        Entity write_entity;
        write_entity.ID(534574);
@@ -226,6 +212,8 @@ void PacketTest::testSpawnEntity() {
        write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
        write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
        write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
+       write_entity.GetState().pitch = 0.3f;
+       write_entity.GetState().yaw = -2.3f;
        write_entity.Bounds({{ -1, -1, -1 }, { 1, 1, 1 }});
        write_entity.WorldCollidable(true);
        write_entity.Name("blah");
@@ -281,12 +269,12 @@ void PacketTest::testDespawnEntity() {
 
 void PacketTest::testEntityUpdate() {
        auto pack = Packet::Make<Packet::EntityUpdate>(udp_pack);
-       AssertPacket("EntityUpdate", 7, 16, 466, pack);
+       AssertPacket("EntityUpdate", 7, 16, 460, pack);
 
        pack.length = Packet::EntityUpdate::GetSize(3);
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "length not correctly set in EntityUpdate packet",
-               size_t(16 + 3 * 45), pack.length
+               size_t(16 + 3 * 37), pack.length
        );
 
        uint32_t write_count = 3;
@@ -314,6 +302,8 @@ void PacketTest::testEntityUpdate() {
        write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
        write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
        write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
+       write_entity.GetState().pitch = 0.3f;
+       write_entity.GetState().yaw = -2.3f;
        pack.WriteEntity(write_entity, write_base, 1);
        pack.WriteEntity(write_entity, write_base, 0);
        pack.WriteEntity(write_entity, write_base, 2);
@@ -334,7 +324,7 @@ void PacketTest::testEntityUpdate() {
 
 void PacketTest::testPlayerCorrection() {
        auto pack = Packet::Make<Packet::PlayerCorrection>(udp_pack);
-       AssertPacket("PlayerCorrection", 8, 52, pack);
+       AssertPacket("PlayerCorrection", 8, 44, pack);
 
        uint16_t write_seq = 50050;
        uint16_t read_seq;
@@ -350,6 +340,8 @@ void PacketTest::testPlayerCorrection() {
        write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
        write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
        write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
+       write_entity.GetState().pitch = 0.3f;
+       write_entity.GetState().yaw = -2.3f;
        pack.WritePlayer(write_entity);
 
        EntityState read_state;
@@ -610,6 +602,14 @@ void PacketTest::AssertEqual(
                message + ": bad orientation",
                expected.orient, actual.orient
        );
+       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+               message + ": bad pitch",
+               expected.pitch, actual.pitch, PI/65534.0f
+       );
+       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+               message + ": bad yaw",
+               expected.yaw, actual.yaw, PI/32767.0f
+       );
 }
 
 void PacketTest::AssertEqual(