-----------
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:
namespace client {
class ChunkTransmission;
+class Client;
class ChunkReceiver {
public:
- ChunkReceiver(ChunkStore &, const WorldSave &);
+ ChunkReceiver(Client &, ChunkStore &, const WorldSave &);
~ChunkReceiver();
void Update(int dt);
ChunkTransmission &GetTransmission(std::uint32_t id);
void Commit(ChunkTransmission &);
+ void ReRequest(ChunkTransmission &);
+
private:
+ Client &client;
ChunkStore &store;
const WorldSave &save;
std::list<ChunkTransmission> transmissions;
ChunkTransmission();
+ void Reset() noexcept;
void Clear() noexcept;
bool Complete() const noexcept;
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,
, 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)
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) {
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) {
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;
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));
}
-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;
}
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,
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();
}
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()) {
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;