]> git.localhorst.tv Git - blank.git/commitdiff
exchange block updates with clients
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 1 Oct 2015 11:20:54 +0000 (13:20 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 1 Oct 2015 15:33:45 +0000 (17:33 +0200)
doc/protocol
src/client/InteractiveState.hpp
src/client/MasterState.hpp
src/client/client.cpp
src/net/ConnectionHandler.hpp
src/net/Packet.hpp
src/net/net.cpp
src/server/ClientConnection.hpp
src/server/net.cpp
tst/net/PacketTest.cpp
tst/net/PacketTest.hpp

index a707d2547538bffcf40e4edb912f404059bd7f9e..3347158e516ff7b567dbd101e65535d7213f3378 100644 (file)
@@ -181,3 +181,18 @@ Payload:
         8 block size, size of the data block, 32bit unsigned int
        12 data, raw data
 Length: 12-484
+
+
+Block Update
+------------
+
+Sent by the server whenever one or more block in a chunk have changed.
+
+Code: 11
+Payload:
+        0 chunk coordinates, vec3i
+       12 number of blocks, 32bit unsigned int, 1-78
+       16 first block index, 16bit unsigned int
+       18 first block data, 32bit
+       22 second block index...
+Length: 16 + multiple of 6, max 484
index 1129e997fdbcfd2f7d1377a73b9b7a61c9d5806a..2db227067711aecb78223231658514eebbb7bf89 100644 (file)
@@ -11,6 +11,7 @@
 #include "../graphics/SkyBox.hpp"
 #include "../io/WorldSave.hpp"
 #include "../model/Skeletons.hpp"
+#include "../net/Packet.hpp"
 #include "../ui/HUD.hpp"
 #include "../ui/InteractiveManipulator.hpp"
 #include "../ui/Interface.hpp"
@@ -48,6 +49,7 @@ public:
        void Render(Viewport &) override;
 
        void MergePlayerCorrection(std::uint16_t, const EntityState &);
+       void Handle(const Packet::BlockUpdate &);
 
        void SetAudio(bool) override;
        void SetVideo(bool) override;
index 3c9b23c38fc571ca63351aabcb205b0862d733eb..1d69998b58f3432f656a78906142704384977921 100644 (file)
@@ -60,6 +60,7 @@ public:
        void On(const Packet::PlayerCorrection &) override;
        void On(const Packet::ChunkBegin &) override;
        void On(const Packet::ChunkData &) override;
+       void On(const Packet::BlockUpdate &) override;
 
 private:
        /// flag entity as updated by given packet
index 524454b43e31a70310f9b0fa377c3a29ec3d8071..91d6aed6992e7327fc23116fcea59c9f902c8c00 100644 (file)
@@ -8,6 +8,7 @@
 #include "../app/TextureIndex.hpp"
 #include "../model/CompositeModel.hpp"
 #include "../io/WorldSave.hpp"
+#include "../world/ChunkIndex.hpp"
 #include "../world/ChunkStore.hpp"
 
 #include <iostream>
@@ -214,6 +215,27 @@ void InteractiveState::MergePlayerCorrection(std::uint16_t pack, const EntitySta
        input.MergePlayerCorrection(pack, state);
 }
 
+void InteractiveState::Handle(const Packet::BlockUpdate &pack) {
+       glm::ivec3 pos;
+       pack.ReadChunkCoords(pos);
+       Chunk *chunk = player.GetChunks().Get(pos);
+       if (!chunk) {
+               // this change doesn't concern us
+               return;
+       }
+       uint32_t count = 0;
+       pack.ReadBlockCount(count);
+       for (uint32_t i = 0; i < count; ++i) {
+               uint16_t index;
+               Block block;
+               pack.ReadIndex(index, i);
+               pack.ReadBlock(block, i);
+               if (index < Chunk::size && block.type < block_types.Size()) {
+                       manip.SetBlock(*chunk, index, block);
+               }
+       }
+}
+
 void InteractiveState::SetAudio(bool b) {
        master.GetConfig().audio.enabled = b;
        if (b) {
@@ -476,5 +498,13 @@ void MasterState::On(const Packet::ChunkData &pack) {
        state->GetChunkReceiver().Handle(pack);
 }
 
+void MasterState::On(const Packet::BlockUpdate &pack) {
+       if (!state) {
+               cout << "received block update, but the world has not been created yet" << endl;
+               return;
+       }
+       state->Handle(pack);
+}
+
 }
 }
index 942826b4329349a9b58f8bd1dad2cccf93ed17be..0f0afdaf1a6d24c3e2cb05396c9de7f31ea1ce4c 100644 (file)
@@ -41,6 +41,7 @@ private:
        virtual void On(const Packet::PlayerCorrection &) { }
        virtual void On(const Packet::ChunkBegin &) { }
        virtual void On(const Packet::ChunkData &) { }
+       virtual void On(const Packet::BlockUpdate &) { }
 
 private:
        unsigned int packets_lost;
index b32b42b5bceee10c901d8335426bb971b81c5746..7b9b69e447289efbd2831503f5e3ea2689ce64e4 100644 (file)
@@ -10,6 +10,7 @@
 
 namespace blank {
 
+class Block;
 class Entity;
 class EntityState;
 
@@ -197,6 +198,26 @@ struct Packet {
                void ReadData(std::uint8_t *, std::size_t maxlen) const noexcept;
        };
 
+       struct BlockUpdate : public Payload {
+               static constexpr std::uint8_t TYPE = 11;
+               static constexpr std::size_t MAX_LEN = 484;
+
+               static constexpr std::uint32_t MAX_BLOCKS = 78;
+               static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
+                       return 16 + (num * 6);
+               }
+
+               void WriteChunkCoords(const glm::ivec3 &) noexcept;
+               void ReadChunkCoords(glm::ivec3 &) const noexcept;
+               void WriteBlockCount(std::uint32_t) noexcept;
+               void ReadBlockCount(std::uint32_t &) const noexcept;
+
+               void WriteIndex(std::uint16_t, std::uint32_t) noexcept;
+               void ReadIndex(std::uint16_t &, std::uint32_t) const noexcept;
+               void WriteBlock(const Block &, std::uint32_t) noexcept;
+               void ReadBlock(Block &, std::uint32_t) const noexcept;
+       };
+
 
        template<class PayloadType>
        PayloadType As() {
index e766c76d0b1201892bd1f0393a0d108f9d640b96..58875e7d0a62e6f584050d67d78fdb6a9a4c73c9 100644 (file)
@@ -26,6 +26,7 @@ constexpr size_t Packet::EntityUpdate::MAX_LEN;
 constexpr size_t Packet::PlayerCorrection::MAX_LEN;
 constexpr size_t Packet::ChunkBegin::MAX_LEN;
 constexpr size_t Packet::ChunkData::MAX_LEN;
+constexpr size_t Packet::BlockUpdate::MAX_LEN;
 
 Connection::Connection(const IPaddress &addr)
 : handler(nullptr)
@@ -211,6 +212,8 @@ const char *Packet::Type2String(uint8_t t) noexcept {
                        return "ChunkBegin";
                case ChunkData::TYPE:
                        return "ChunkData";
+               case BlockUpdate::TYPE:
+                       return "BlockUpdate";
                default:
                        return "Unknown";
        }
@@ -502,6 +505,42 @@ void Packet::ChunkData::ReadData(uint8_t *d, size_t l) const noexcept {
        memcpy(d, &data[12], len);
 }
 
+void Packet::BlockUpdate::WriteChunkCoords(const glm::ivec3 &coords) noexcept {
+       Write(coords, 0);
+}
+
+void Packet::BlockUpdate::ReadChunkCoords(glm::ivec3 &coords) const noexcept {
+       Read(coords, 0);
+}
+
+void Packet::BlockUpdate::WriteBlockCount(uint32_t count) noexcept {
+       Write(count, 12);
+}
+
+void Packet::BlockUpdate::ReadBlockCount(uint32_t &count) const noexcept {
+       Read(count, 12);
+}
+
+void Packet::BlockUpdate::WriteIndex(uint16_t index, uint32_t num) noexcept {
+       uint32_t off = GetSize(num);
+       Write(index, off);
+}
+
+void Packet::BlockUpdate::ReadIndex(uint16_t &index, uint32_t num) const noexcept {
+       uint32_t off = GetSize(num);
+       Read(index, off);
+}
+
+void Packet::BlockUpdate::WriteBlock(const Block &block, uint32_t num) noexcept {
+       uint32_t off = GetSize(num) + 2;
+       Write(block, off);
+}
+
+void Packet::BlockUpdate::ReadBlock(Block &block, uint32_t num) const noexcept {
+       uint32_t off = GetSize(num) + 2;
+       Read(block, off);
+}
+
 
 void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
        const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
@@ -539,6 +578,9 @@ void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
                case Packet::ChunkData::TYPE:
                        On(Packet::As<Packet::ChunkData>(udp_pack));
                        break;
+               case Packet::BlockUpdate::TYPE:
+                       On(Packet::As<Packet::BlockUpdate>(udp_pack));
+                       break;
                default:
                        // drop unknown or unhandled packets
                        break;
index 4927d1ce831fb9ab26c15cbeb68db9826b3c497c..9aaae128d4c43ead42c6fac689f0b006cae3025b 100644 (file)
@@ -61,6 +61,8 @@ public:
        bool HasPlayerModel() const noexcept;
        const CompositeModel &GetPlayerModel() const noexcept;
 
+       bool ChunkInRange(const glm::ivec3 &) const noexcept;
+
 private:
        struct SpawnStatus {
                // the entity in question
index ea5b4d995f19d38262891b0919f1fb2360ed05b3..8b4448e46d6b363051d755f8fe6f05c2d2c871ca 100644 (file)
@@ -283,7 +283,7 @@ uint16_t ClientConnection::Send() {
 }
 
 uint16_t ClientConnection::Send(size_t len) {
-       server.GetPacket().len = len;
+       server.GetPacket().len = sizeof(Packet::Header) + len;
        return Send();
 }
 
@@ -555,6 +555,10 @@ void ClientConnection::On(const Packet::PlayerUpdate &pack) {
        old_actions = new_actions;
 }
 
+bool ClientConnection::ChunkInRange(const glm::ivec3 &pos) const noexcept {
+       return HasPlayer() && PlayerChunks().InRange(pos);
+}
+
 
 Server::Server(const Config::Network &conf, World &world)
 : serv_sock(nullptr)
@@ -645,8 +649,18 @@ const CompositeModel &Server::GetPlayerModel() const noexcept {
 
 void Server::SetBlock(Chunk &chunk, int index, const Block &block) {
        chunk.SetBlock(index, block);
-       // TODO: send to clients
-       // also TODO: batch chunk changes
+       // TODO: batch chunk changes
+       auto pack = Packet::Make<Packet::BlockUpdate>(GetPacket());
+       pack.WriteChunkCoords(chunk.Position());
+       pack.WriteBlockCount(uint32_t(1));
+       pack.WriteIndex(index, 0);
+       pack.WriteBlock(chunk.BlockAt(index), 0);
+       GetPacket().len = sizeof(Packet::Header) + Packet::BlockUpdate::GetSize(1);
+       for (ClientConnection &client : clients) {
+               if (client.ChunkInRange(chunk.Position())) {
+                       client.Send();
+               }
+       }
 }
 
 }
index 42d83480610f14842857ec8a52f78b60b0441247..751421b2f9bcb351090c34776ea4c777adbceec9 100644 (file)
@@ -25,6 +25,25 @@ static constexpr uint32_t TEST_TAG = 0xFB1AB1AF;
 
 }
 
+void PacketTest::testSizes() {
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "unexpected size of vec3",
+               size_t(12), sizeof(glm::vec3)
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "unexpected size of vec3i",
+               size_t(12), sizeof(glm::ivec3)
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "unexpected size of quat",
+               size_t(16), sizeof(glm::quat)
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "unexpected size of entity state",
+               size_t(64), sizeof(EntityState)
+       );
+}
+
 void PacketTest::testControl() {
        Packet::TControl ctrl;
        ctrl.ack = 10;
@@ -278,7 +297,7 @@ void PacketTest::testEntityUpdate() {
 
        pack.length = Packet::EntityUpdate::GetSize(3);
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
-               "length not correctly set in DespawnEntity packet",
+               "length not correctly set in EntityUpdate packet",
                size_t(4 + 3 * 68), pack.length
        );
 
@@ -432,6 +451,66 @@ void PacketTest::testChunkData() {
        );
 }
 
+void PacketTest::testBlockUpdate() {
+       auto pack = Packet::Make<Packet::BlockUpdate>(udp_pack);
+       AssertPacket("BlockUpdate", 11, 16, 484, pack);
+
+       pack.length = Packet::BlockUpdate::GetSize(3);
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "length not correctly set in BlockUpdate packet",
+               size_t(16 + 3 * 6), pack.length
+       );
+
+       glm::ivec3 write_coords(432, -325, 99998);
+       uint32_t write_count = 3;
+       uint16_t write_index = 432;
+       Block write_block(324, Block::FACE_DOWN, Block::TURN_AROUND);
+
+       pack.WriteChunkCoords(write_coords);
+       pack.WriteBlockCount(write_count);
+       pack.WriteIndex(write_index, 1);
+       pack.WriteBlock(write_block, 1);
+       pack.WriteIndex(write_index, 0);
+       pack.WriteBlock(write_block, 0);
+       pack.WriteIndex(write_index, 2);
+       pack.WriteBlock(write_block, 2);
+
+       glm::ivec3 read_coords;
+       uint32_t read_count;
+       uint16_t read_index;
+       Block read_block;
+
+       pack.ReadChunkCoords(read_coords);
+       pack.ReadBlockCount(read_count);
+       pack.ReadIndex(read_index, 1);
+       pack.ReadBlock(read_block, 1);
+
+       AssertEqual(
+               "chunk coordinates not correctly transported in BlockUpdate packet",
+               write_coords, read_coords
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "block count not correctly transported in BlockUpdate packet",
+               write_count, read_count
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "block index not correctly transported in BlockUpdate packet",
+               write_index, read_index
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "block type not correctly transported in BlockUpdate packet",
+               write_block.type, read_block.type
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "block face not correctly transported in BlockUpdate packet",
+               write_block.GetFace(), read_block.GetFace()
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "block turn not correctly transported in BlockUpdate packet",
+               write_block.GetTurn(), read_block.GetTurn()
+       );
+}
+
 
 void PacketTest::AssertPacket(
        const string &name,
index 89e15dd526e35982ec69d6630c924cdc3a603e5c..32976c8429ba61e8f709c0cb8d76c62b4f0456fc 100644 (file)
@@ -21,6 +21,7 @@ class PacketTest
 
 CPPUNIT_TEST_SUITE(PacketTest);
 
+CPPUNIT_TEST(testSizes);
 CPPUNIT_TEST(testControl);
 CPPUNIT_TEST(testPing);
 CPPUNIT_TEST(testLogin);
@@ -33,6 +34,7 @@ CPPUNIT_TEST(testEntityUpdate);
 CPPUNIT_TEST(testPlayerCorrection);
 CPPUNIT_TEST(testChunkBegin);
 CPPUNIT_TEST(testChunkData);
+CPPUNIT_TEST(testBlockUpdate);
 
 CPPUNIT_TEST_SUITE_END();
 
@@ -40,6 +42,7 @@ public:
        void setUp();
        void tearDown();
 
+       void testSizes();
        void testControl();
        void testPing();
        void testLogin();
@@ -52,6 +55,7 @@ public:
        void testPlayerCorrection();
        void testChunkBegin();
        void testChunkData();
+       void testBlockUpdate();
 
 private:
        static void AssertPacket(