1 #include "ChunkReceiver.hpp"
2 #include "ChunkTransmission.hpp"
5 #include "../app/init.hpp"
6 #include "../net/Packet.hpp"
7 #include "../world/Chunk.hpp"
8 #include "../world/ChunkStore.hpp"
12 #include <glm/gtx/io.hpp>
21 ChunkReceiver::ChunkReceiver(ChunkStore &store)
28 ChunkReceiver::~ChunkReceiver() {
32 void ChunkReceiver::Update(int dt) {
34 for (ChunkTransmission &trans : transmissions) {
35 if (trans.active && (timer.Elapsed() - trans.last_update) > timer.Interval()) {
36 cout << "timeout for transmission of chunk " << trans.coords << endl;
40 if (transmissions.size() > 3) {
41 for (auto iter = transmissions.begin(), end = transmissions.end(); iter != end; ++iter) {
43 transmissions.erase(iter);
50 void ChunkReceiver::Handle(const Packet::ChunkBegin &pack) {
52 pack.ReadTransmissionId(id);
53 ChunkTransmission &trans = GetTransmission(id);
54 pack.ReadFlags(trans.flags);
55 pack.ReadChunkCoords(trans.coords);
56 pack.ReadDataSize(trans.data_size);
57 trans.last_update = timer.Elapsed();
58 trans.header_received = true;
62 void ChunkReceiver::Handle(const Packet::ChunkData &pack) {
63 uint32_t id, pos, size;
64 pack.ReadTransmissionId(id);
65 pack.ReadDataOffset(pos);
66 if (pos >= sizeof(ChunkTransmission::buffer)) {
67 cout << "received chunk data offset outside of buffer size" << endl;
70 pack.ReadDataSize(size);
71 ChunkTransmission &trans = GetTransmission(id);
72 size_t len = min(size_t(size), sizeof(ChunkTransmission::buffer) - pos);
73 pack.ReadData(&trans.buffer[pos], len);
74 // TODO: this method breaks when a packet arrives twice
75 trans.data_received += len;
76 trans.last_update = timer.Elapsed();
80 ChunkTransmission &ChunkReceiver::GetTransmission(uint32_t id) {
82 for (ChunkTransmission &trans : transmissions) {
83 if (trans.active && trans.id == id) {
88 for (ChunkTransmission &trans : transmissions) {
96 transmissions.emplace_back();
97 transmissions.back().active = true;
98 transmissions.back().id = id;
99 return transmissions.back();
102 void ChunkReceiver::Commit(ChunkTransmission &trans) {
103 if (!trans.Complete()) return;
105 Chunk *chunk = store.Allocate(trans.coords);
107 // chunk no longer of interes, just drop the data
108 // it should probably be cached to disk, but not now :P
113 const Byte *src = &trans.buffer[0];
114 uLong src_len = min(size_t(trans.data_size), sizeof(ChunkTransmission::buffer));
115 Byte *dst = reinterpret_cast<Byte *>(chunk->BlockData());
116 uLong dst_len = Chunk::BlockSize();
118 if (trans.Compressed()) {
119 if (uncompress(dst, &dst_len, src, src_len) != Z_OK) {
121 cout << "got corruped chunk data for " << trans.coords << endl;
124 memcpy(dst, src, min(src_len, dst_len));
130 ChunkTransmission::ChunkTransmission()
137 , header_received(false)
143 void ChunkTransmission::Clear() noexcept {
147 header_received = false;
151 bool ChunkTransmission::Complete() const noexcept {
152 return header_received && data_received == data_size;
155 bool ChunkTransmission::Compressed() const noexcept {
162 UDPsocket client_bind(Uint16 port) {
163 UDPsocket sock = SDLNet_UDP_Open(port);
165 throw NetError("SDLNet_UDP_Open");
170 IPaddress client_resolve(const char *host, Uint16 port) {
172 if (SDLNet_ResolveHost(&addr, host, port) != 0) {
173 throw NetError("SDLNet_ResolveHost");
180 Client::Client(const Config &conf)
181 : conn(client_resolve(conf.host.c_str(), conf.port))
182 , client_sock(client_bind(0))
183 , client_pack{ -1, nullptr, 0 } {
184 client_pack.data = new Uint8[sizeof(Packet)];
185 client_pack.maxlen = sizeof(Packet);
186 // establish connection
191 delete[] client_pack.data;
192 SDLNet_UDP_Close(client_sock);
196 void Client::Handle() {
197 int result = SDLNet_UDP_Recv(client_sock, &client_pack);
199 HandlePacket(client_pack);
200 result = SDLNet_UDP_Recv(client_sock, &client_pack);
203 // a boo boo happened
204 throw NetError("SDLNet_UDP_Recv");
208 void Client::HandlePacket(const UDPpacket &udp_pack) {
209 if (!conn.Matches(udp_pack.address)) {
210 // packet came from somewhere else, drop
213 const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
214 if (pack.header.tag != Packet::TAG) {
215 // mistagged packet, drop
219 conn.Received(udp_pack);
222 void Client::Update(int dt) {
224 if (conn.ShouldPing()) {
229 uint16_t Client::SendPing() {
230 return conn.SendPing(client_pack, client_sock);
233 uint16_t Client::SendLogin(const string &name) {
234 auto pack = Packet::Make<Packet::Login>(client_pack);
235 pack.WritePlayerName(name);
236 return conn.Send(client_pack, client_sock);
239 uint16_t Client::SendPlayerUpdate(const Entity &player) {
240 auto pack = Packet::Make<Packet::PlayerUpdate>(client_pack);
241 pack.WritePlayer(player);
242 return conn.Send(client_pack, client_sock);
245 uint16_t Client::SendPart() {
246 Packet::Make<Packet::Part>(client_pack);
247 return conn.Send(client_pack, client_sock);