]> git.localhorst.tv Git - blank.git/commitdiff
re-request incomplete or corrupted chunk transfers
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 13 Nov 2015 11:31:27 +0000 (12:31 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 13 Nov 2015 11:31:27 +0000 (12:31 +0100)
doc/protocol
src/client/ChunkReceiver.hpp
src/client/ChunkTransmission.hpp
src/client/Client.hpp
src/client/client.cpp
src/client/net.cpp
src/server/ClientConnection.hpp
src/server/net.cpp

index 8e2694970ce596b049b2facb4aa313634214b085..f194d77d3ce28a7bcb17ab676efb87bb705ec860 100644 (file)
@@ -170,6 +170,10 @@ Chunk Begin
 -----------
 
 Sent by the server to inform the client of an upcoming chunk transmission.
+The client may send this packet to the server to re-request a chunk
+transmission.  In that case fields other than the chunk coordinates are
+ignored. Also, the server may choose not to resend the chunk (e.g. if the
+player is too far away from it).
 
 Code: 9
 Payload:
index 57c1cebbc1255118e1f39f3ad266d60bef8936eb..d682d1e7f2b9251ecdaf2a81e583f2c44fbf5631 100644 (file)
@@ -16,11 +16,12 @@ class WorldSave;
 namespace client {
 
 class ChunkTransmission;
+class Client;
 
 class ChunkReceiver {
 
 public:
-       ChunkReceiver(ChunkStore &, const WorldSave &);
+       ChunkReceiver(Client &, ChunkStore &, const WorldSave &);
        ~ChunkReceiver();
 
        void Update(int dt);
@@ -39,7 +40,10 @@ private:
        ChunkTransmission &GetTransmission(std::uint32_t id);
        void Commit(ChunkTransmission &);
 
+       void ReRequest(ChunkTransmission &);
+
 private:
+       Client &client;
        ChunkStore &store;
        const WorldSave &save;
        std::list<ChunkTransmission> transmissions;
index f54c7d8a2182d3daec20795c67794ebd34c42d99..7e801eec3b24880d8477d4668dd3e0d5ee180bd0 100644 (file)
@@ -28,6 +28,7 @@ struct ChunkTransmission {
 
        ChunkTransmission();
 
+       void Reset() noexcept;
        void Clear() noexcept;
 
        bool Complete() const noexcept;
index e124ae51200dd8d169a6a000bf98d6489d39a846..b09001cda1d40a1e096f9883eb19ee391298d499 100644 (file)
@@ -37,6 +37,8 @@ public:
                float yaw,
                std::uint8_t actions,
                std::uint8_t slot);
+       std::uint16_t SendChunkRequest(
+               const glm::ivec3 &);
        std::uint16_t SendMessage(
                std::uint8_t type,
                std::uint32_t ref,
index 5a34976358d8ee74cc4826b464a7d9ff9668a8e6..232ba250eaa9236ff4fd9a4603a85ab9449536f9 100644 (file)
@@ -56,7 +56,7 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id)
 , manip(master.GetEnv().audio, sounds, player.GetEntity())
 , input(world, player, master.GetClient())
 , interface(master.GetConfig(), master.GetEnv().keymap, input, *this)
-, chunk_receiver(world.Chunks(), save)
+, chunk_receiver(master.GetClient(), world.Chunks(), save)
 , chunk_renderer(player.GetChunks())
 , loop_timer(16)
 , stat_timer(1000)
index d7a2661d56c3bc54d09df6140da9a003fed848db..75865be577dfac866df3ac302ac85f0a491e440e 100644 (file)
@@ -23,8 +23,9 @@ namespace blank {
 namespace client {
 
 
-ChunkReceiver::ChunkReceiver(ChunkStore &store, const WorldSave &save)
-: store(store)
+ChunkReceiver::ChunkReceiver(Client &client, ChunkStore &store, const WorldSave &save)
+: client(client)
+, store(store)
 , save(save)
 , transmissions()
 , timer(5000) {
@@ -40,7 +41,14 @@ void ChunkReceiver::Update(int dt) {
        for (ChunkTransmission &trans : transmissions) {
                if (trans.active && (timer.Elapsed() - trans.last_update) > timer.Interval()) {
                        cout << "timeout for transmission of chunk " << trans.coords << endl;
-                       trans.Clear();
+                       if (trans.header_received) {
+                               client.SendChunkRequest(trans.coords);
+                               trans.Reset();
+                               trans.last_update = timer.Elapsed();
+                       } else {
+                               // well shit
+                               trans.Clear();
+                       }
                }
        }
        if (transmissions.size() > 3) {
@@ -152,7 +160,7 @@ void ChunkReceiver::Commit(ChunkTransmission &trans) {
 
        Chunk *chunk = store.Allocate(trans.coords);
        if (!chunk) {
-               // chunk no longer of interes, just drop the data
+               // chunk no longer of interest, just drop the data
                // it should probably be cached to disk, but not now :P
                trans.Clear();
                return;
@@ -167,6 +175,12 @@ void ChunkReceiver::Commit(ChunkTransmission &trans) {
                if (uncompress(dst, &dst_len, src, src_len) != Z_OK) {
                        // omg, now what?
                        cout << "got corruped chunk data for " << trans.coords << endl;
+                       client.SendChunkRequest(trans.coords);
+                       trans.Reset();
+                       // chunk data can, and probably will, contain invalid block IDs, so
+                       // zero it to be safe
+                       memset(dst, 0, dst_len);
+                       return;
                }
        } else {
                memcpy(dst, src, min(src_len, dst_len));
@@ -188,11 +202,15 @@ ChunkTransmission::ChunkTransmission()
 
 }
 
-void ChunkTransmission::Clear() noexcept {
+void ChunkTransmission::Reset() noexcept {
        data_size = 0;
        data_received = 0;
        last_update = 0;
        header_received = false;
+}
+
+void ChunkTransmission::Clear() noexcept {
+       Reset();
        active = false;
 }
 
@@ -305,6 +323,14 @@ uint16_t Client::SendPart() {
        return conn.Send(client_pack, client_sock);
 }
 
+uint16_t Client::SendChunkRequest(
+       const glm::ivec3 &coords
+) {
+       auto pack = Packet::Make<Packet::ChunkBegin>(client_pack);
+       pack.WriteChunkCoords(coords);
+       return conn.Send(client_pack, client_sock);
+}
+
 uint16_t Client::SendMessage(
        uint8_t type,
        uint32_t ref,
index bd42241d9974897a8210afc3479e500c3e6e1c53..57a34e49339a965655a170758a82603558bc6155 100644 (file)
@@ -83,6 +83,7 @@ private:
        void On(const Packet::Login &) override;
        void On(const Packet::Part &) override;
        void On(const Packet::PlayerUpdate &) override;
+       void On(const Packet::ChunkBegin &) override;
        void On(const Packet::Message &) override;
 
        void CheckEntities();
index 7947c221beb13d803a9b6c6a0c9d14a56f190e8d..d16088991f22f2a840869dc1c9da89c040764cbe 100644 (file)
@@ -401,6 +401,7 @@ void ClientConnection::CheckChunkQueue() {
                }
                old_base = PlayerChunks().Base();
                sort(chunk_queue.begin(), chunk_queue.end(), QueueCompare(old_base));
+               chunk_queue.erase(unique(chunk_queue.begin(), chunk_queue.end()), chunk_queue.end());
        }
        // don't push entity updates and chunk data in the same tick
        if (chunk_blocks_skipped >= NetStat().SuggestedPacketHold() && !SendingUpdates()) {
@@ -612,6 +613,14 @@ bool ClientConnection::ChunkInRange(const glm::ivec3 &pos) const noexcept {
        return HasPlayer() && PlayerChunks().InRange(pos);
 }
 
+void ClientConnection::On(const Packet::ChunkBegin &pack) {
+       glm::ivec3 pos;
+       pack.ReadChunkCoords(pos);
+       if (ChunkInRange(pos)) {
+               chunk_queue.push_front(pos);
+       }
+}
+
 void ClientConnection::On(const Packet::Message &pack) {
        uint8_t type;
        uint32_t ref;