]> git.localhorst.tv Git - blank.git/blob - src/net/net.cpp
send entity visual from server to client
[blank.git] / src / net / net.cpp
1 #include "Client.hpp"
2 #include "ClientConnection.hpp"
3 #include "Connection.hpp"
4 #include "ConnectionHandler.hpp"
5 #include "io.hpp"
6 #include "Packet.hpp"
7 #include "Server.hpp"
8
9 #include "../app/init.hpp"
10 #include "../model/CompositeModel.hpp"
11 #include "../world/World.hpp"
12
13 #include <cstring>
14 #include <iostream>
15 #include <glm/gtx/io.hpp>
16
17 using namespace std;
18
19
20 namespace blank {
21
22 constexpr size_t Packet::Ping::MAX_LEN;
23 constexpr size_t Packet::Login::MAX_LEN;
24 constexpr size_t Packet::Join::MAX_LEN;
25 constexpr size_t Packet::Part::MAX_LEN;
26 constexpr size_t Packet::PlayerUpdate::MAX_LEN;
27 constexpr size_t Packet::SpawnEntity::MAX_LEN;
28 constexpr size_t Packet::DespawnEntity::MAX_LEN;
29 constexpr size_t Packet::EntityUpdate::MAX_LEN;
30
31 namespace {
32
33 UDPsocket client_bind(Uint16 port) {
34         UDPsocket sock = SDLNet_UDP_Open(port);
35         if (!sock) {
36                 throw NetError("SDLNet_UDP_Open");
37         }
38         return sock;
39 }
40
41 IPaddress client_resolve(const char *host, Uint16 port) {
42         IPaddress addr;
43         if (SDLNet_ResolveHost(&addr, host, port) != 0) {
44                 throw NetError("SDLNet_ResolveHost");
45         }
46         return addr;
47 }
48
49 }
50
51 Client::Client(const Config &conf)
52 : conn(client_resolve(conf.host.c_str(), conf.port))
53 , client_sock(client_bind(0))
54 , client_pack{ -1, nullptr, 0 } {
55         client_pack.data = new Uint8[sizeof(Packet)];
56         client_pack.maxlen = sizeof(Packet);
57         // establish connection
58         SendPing();
59 }
60
61 Client::~Client() {
62         delete[] client_pack.data;
63         SDLNet_UDP_Close(client_sock);
64 }
65
66
67 void Client::Handle() {
68         int result = SDLNet_UDP_Recv(client_sock, &client_pack);
69         while (result > 0) {
70                 HandlePacket(client_pack);
71                 result = SDLNet_UDP_Recv(client_sock, &client_pack);
72         }
73         if (result == -1) {
74                 // a boo boo happened
75                 throw NetError("SDLNet_UDP_Recv");
76         }
77 }
78
79 void Client::HandlePacket(const UDPpacket &udp_pack) {
80         if (!conn.Matches(udp_pack.address)) {
81                 // packet came from somewhere else, drop
82                 return;
83         }
84         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
85         if (pack.header.tag != Packet::TAG) {
86                 // mistagged packet, drop
87                 return;
88         }
89
90         conn.Received(udp_pack);
91 }
92
93 void Client::Update(int dt) {
94         conn.Update(dt);
95         if (conn.ShouldPing()) {
96                 SendPing();
97         }
98 }
99
100 uint16_t Client::SendPing() {
101         return conn.SendPing(client_pack, client_sock);
102 }
103
104 uint16_t Client::SendLogin(const string &name) {
105         auto pack = Packet::Make<Packet::Login>(client_pack);
106         pack.WritePlayerName(name);
107         return conn.Send(client_pack, client_sock);
108 }
109
110 uint16_t Client::SendPlayerUpdate(const Entity &player) {
111         auto pack = Packet::Make<Packet::PlayerUpdate>(client_pack);
112         pack.WritePlayer(player);
113         return conn.Send(client_pack, client_sock);
114 }
115
116 uint16_t Client::SendPart() {
117         Packet::Make<Packet::Part>(client_pack);
118         return conn.Send(client_pack, client_sock);
119 }
120
121
122 ClientConnection::ClientConnection(Server &server, const IPaddress &addr)
123 : server(server)
124 , conn(addr)
125 , player(nullptr)
126 , spawns()
127 , confirm_wait(0) {
128         conn.SetHandler(this);
129 }
130
131 ClientConnection::~ClientConnection() {
132         DetachPlayer();
133 }
134
135 void ClientConnection::Update(int dt) {
136         conn.Update(dt);
137         if (Disconnected()) {
138                 return;
139         }
140         if (HasPlayer()) {
141                 // sync entities
142                 auto global_iter = server.GetWorld().Entities().begin();
143                 auto global_end = server.GetWorld().Entities().end();
144                 auto local_iter = spawns.begin();
145                 auto local_end = spawns.end();
146
147                 while (global_iter != global_end && local_iter != local_end) {
148                         if (global_iter->ID() == local_iter->entity->ID()) {
149                                 // they're the same
150                                 if (CanDespawn(*global_iter)) {
151                                         SendDespawn(*local_iter);
152                                 } else {
153                                         // update
154                                         SendUpdate(*local_iter);
155                                 }
156                                 ++global_iter;
157                                 ++local_iter;
158                         } else if (global_iter->ID() < local_iter->entity->ID()) {
159                                 // global entity was inserted
160                                 if (CanSpawn(*global_iter)) {
161                                         auto spawned = spawns.emplace(local_iter, *global_iter);
162                                         SendSpawn(*spawned);
163                                 }
164                                 ++global_iter;
165                         } else {
166                                 // global entity was removed
167                                 SendDespawn(*local_iter);
168                                 ++local_iter;
169                         }
170                 }
171
172                 // leftover spawns
173                 while (global_iter != global_end) {
174                         if (CanSpawn(*global_iter)) {
175                                 spawns.emplace_back(*global_iter);
176                                 SendSpawn(spawns.back());
177                         }
178                         ++global_iter;
179                 }
180
181                 // leftover despawns
182                 while (local_iter != local_end) {
183                         SendDespawn(*local_iter);
184                         ++local_iter;
185                 }
186         }
187         if (conn.ShouldPing()) {
188                 conn.SendPing(server.GetPacket(), server.GetSocket());
189         }
190 }
191
192 ClientConnection::SpawnStatus::SpawnStatus(Entity &e)
193 : entity(&e)
194 , spawn_pack(-1)
195 , despawn_pack(-1) {
196         entity->Ref();
197 }
198
199 ClientConnection::SpawnStatus::~SpawnStatus() {
200         entity->UnRef();
201 }
202
203 bool ClientConnection::CanSpawn(const Entity &e) const noexcept {
204         return
205                 &e != player &&
206                 !e.Dead() &&
207                 manhattan_radius(e.ChunkCoords() - Player().ChunkCoords()) < 7;
208 }
209
210 bool ClientConnection::CanDespawn(const Entity &e) const noexcept {
211         return
212                 e.Dead() ||
213                 manhattan_radius(e.ChunkCoords() - Player().ChunkCoords()) > 7;
214 }
215
216 void ClientConnection::SendSpawn(SpawnStatus &status) {
217         // don't double spawn
218         if (status.spawn_pack != -1) return;
219
220         auto pack = Packet::Make<Packet::SpawnEntity>(server.GetPacket());
221         pack.WriteEntity(*status.entity);
222         status.spawn_pack = conn.Send(server.GetPacket(), server.GetSocket());
223         ++confirm_wait;
224 }
225
226 void ClientConnection::SendDespawn(SpawnStatus &status) {
227         // don't double despawn
228         if (status.despawn_pack != -1) return;
229
230         auto pack = Packet::Make<Packet::DespawnEntity>(server.GetPacket());
231         pack.WriteEntityID(status.entity->ID());
232         status.despawn_pack = conn.Send(server.GetPacket(), server.GetSocket());
233         ++confirm_wait;
234 }
235
236 void ClientConnection::SendUpdate(SpawnStatus &status) {
237         // don't send updates while spawn not ack'd or despawn sent
238         if (status.spawn_pack != -1 || status.despawn_pack != -1) return;
239
240         // TODO: pack entity updates
241         auto pack = Packet::Make<Packet::EntityUpdate>(server.GetPacket());
242         pack.WriteEntityCount(1);
243         pack.WriteEntity(*status.entity, 0);
244         server.GetPacket().len = Packet::EntityUpdate::GetSize(1);
245         conn.Send(server.GetPacket(), server.GetSocket());
246 }
247
248 void ClientConnection::AttachPlayer(Entity &new_player) {
249         DetachPlayer();
250         player = &new_player;
251         player->Ref();
252         cout << "player \"" << player->Name() << "\" joined" << endl;
253 }
254
255 void ClientConnection::DetachPlayer() {
256         if (!player) return;
257         player->Kill();
258         player->UnRef();
259         cout << "player \"" << player->Name() << "\" left" << endl;
260         player = nullptr;
261 }
262
263 void ClientConnection::OnPacketReceived(uint16_t seq) {
264         if (!confirm_wait) return;
265         for (auto iter = spawns.begin(), end = spawns.end(); iter != end; ++iter) {
266                 if (seq == iter->spawn_pack) {
267                         iter->spawn_pack = -1;
268                         --confirm_wait;
269                         return;
270                 }
271                 if (seq == iter->despawn_pack) {
272                         spawns.erase(iter);
273                         --confirm_wait;
274                         return;
275                 }
276         }
277 }
278
279 void ClientConnection::OnPacketLost(uint16_t seq) {
280         if (!confirm_wait) return;
281         for (SpawnStatus &status : spawns) {
282                 if (seq == status.spawn_pack) {
283                         status.spawn_pack = -1;
284                         --confirm_wait;
285                         SendSpawn(status);
286                         return;
287                 }
288                 if (seq == status.despawn_pack) {
289                         status.despawn_pack = -1;
290                         --confirm_wait;
291                         SendDespawn(status);
292                         return;
293                 }
294         }
295 }
296
297 void ClientConnection::On(const Packet::Login &pack) {
298         string name;
299         pack.ReadPlayerName(name);
300
301         Entity *new_player = server.GetWorld().AddPlayer(name).entity;
302
303         if (new_player) {
304                 // success!
305                 AttachPlayer(*new_player);
306                 cout << "accepted login from player \"" << name << '"' << endl;
307                 auto response = Packet::Make<Packet::Join>(server.GetPacket());
308                 response.WritePlayer(*new_player);
309                 response.WriteWorldName(server.GetWorld().Name());
310                 conn.Send(server.GetPacket(), server.GetSocket());
311         } else {
312                 // aw no :(
313                 cout << "rejected login from player \"" << name << '"' << endl;
314                 Packet::Make<Packet::Part>(server.GetPacket());
315                 conn.Send(server.GetPacket(), server.GetSocket());
316                 conn.Close();
317         }
318 }
319
320 void ClientConnection::On(const Packet::Part &) {
321         conn.Close();
322 }
323
324 void ClientConnection::On(const Packet::PlayerUpdate &pack) {
325         if (!HasPlayer()) return;
326         pack.ReadPlayer(Player());
327 }
328
329
330 Connection::Connection(const IPaddress &addr)
331 : handler(nullptr)
332 , addr(addr)
333 , send_timer(500)
334 , recv_timer(10000)
335 , ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF }
336 , ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF }
337 , closed(false) {
338         send_timer.Start();
339         recv_timer.Start();
340 }
341
342 bool Connection::Matches(const IPaddress &remote) const noexcept {
343         return memcmp(&addr, &remote, sizeof(IPaddress)) == 0;
344 }
345
346 void Connection::FlagSend() noexcept {
347         send_timer.Reset();
348 }
349
350 void Connection::FlagRecv() noexcept {
351         recv_timer.Reset();
352 }
353
354 bool Connection::ShouldPing() const noexcept {
355         return !closed && send_timer.HitOnce();
356 }
357
358 bool Connection::TimedOut() const noexcept {
359         return recv_timer.HitOnce();
360 }
361
362 void Connection::Update(int dt) {
363         send_timer.Update(dt);
364         recv_timer.Update(dt);
365         if (TimedOut()) {
366                 Close();
367                 if (HasHandler()) {
368                         Handler().OnTimeout();
369                 }
370         }
371 }
372
373
374 uint16_t Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
375         Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
376         pack.header.ctrl = ctrl_out;
377         uint16_t seq = ctrl_out.seq++;
378
379         udp_pack.address = addr;
380         if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
381                 throw NetError("SDLNet_UDP_Send");
382         }
383
384         FlagSend();
385         return seq;
386 }
387
388 void Connection::Received(const UDPpacket &udp_pack) {
389         Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
390
391         // ack to the remote
392         int16_t diff = int16_t(pack.header.ctrl.seq) - int16_t(ctrl_out.ack);
393         if (diff > 0) {
394                 if (diff >= 32) {
395                         ctrl_out.hist = 0;
396                 } else {
397                         ctrl_out.hist <<= diff;
398                         ctrl_out.hist |= 1 << (diff - 1);
399                 }
400         } else if (diff < 0 && diff >= -32) {
401                 ctrl_out.hist |= 1 << (-diff - 1);
402         }
403         ctrl_out.ack = pack.header.ctrl.seq;
404         FlagRecv();
405
406         if (!HasHandler()) {
407                 return;
408         }
409
410         Packet::TControl ctrl_new = pack.header.ctrl;
411         Handler().Handle(udp_pack);
412
413         if (diff > 0) {
414                 // if the packet holds more recent information
415                 // check if remote failed to ack one of our packets
416                 diff = int16_t(ctrl_new.ack) - int16_t(ctrl_in.ack);
417                 // should always be true, but you never know…
418                 if (diff > 0) {
419                         for (int i = 0; i < diff; ++i) {
420                                 if (i > 32 || (i < 32 && (ctrl_in.hist & (1 << (31 - i))) == 0)) {
421                                         Handler().OnPacketLost(ctrl_in.ack - 32 + i);
422                                 }
423                         }
424                 }
425                 // check for newly ack'd packets
426                 for (uint16_t s = ctrl_new.AckBegin(); s != ctrl_new.AckEnd(); ++s) {
427                         if (ctrl_new.Acks(s) && !ctrl_in.Acks(s)) {
428                                 Handler().OnPacketReceived(s);
429                         }
430                 }
431                 ctrl_in = ctrl_new;
432         }
433 }
434
435 bool Packet::TControl::Acks(uint16_t s) const noexcept {
436         int16_t diff = int16_t(ack) - int16_t(s);
437         if (diff == 0) return true;
438         if (diff < 0 || diff > 32) return false;
439         return (hist & (1 << (diff - 1))) != 0;
440 }
441
442 uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
443         Packet::Make<Packet::Ping>(udp_pack);
444         return Send(udp_pack, sock);
445 }
446
447
448 ostream &operator <<(ostream &out, const IPaddress &addr) {
449         const unsigned char *host = reinterpret_cast<const unsigned char *>(&addr.host);
450         out << int(host[0])
451                 << '.' << int(host[1])
452                 << '.' << int(host[2])
453                 << '.' << int(host[3]);
454         if (addr.port) {
455                 out << ':' << SDLNet_Read16(&addr.port);
456         }
457         return out;
458 }
459
460
461 const char *Packet::Type2String(uint8_t t) noexcept {
462         switch (t) {
463                 case Ping::TYPE:
464                         return "Ping";
465                 case Login::TYPE:
466                         return "Login";
467                 case Join::TYPE:
468                         return "Join";
469                 case Part::TYPE:
470                         return "Part";
471                 case PlayerUpdate::TYPE:
472                         return "PlayerUpdate";
473                 case SpawnEntity::TYPE:
474                         return "SpawnEntity";
475                 case DespawnEntity::TYPE:
476                         return "DespawnEntity";
477                 case EntityUpdate::TYPE:
478                         return "EntityUpdate";
479                 default:
480                         return "Unknown";
481         }
482 }
483
484 template<class T>
485 void Packet::Payload::Write(const T &src, size_t off) noexcept {
486         if ((length - off) < sizeof(T)) {
487                 // dismiss out of bounds write
488                 return;
489         }
490         *reinterpret_cast<T *>(&data[off]) = src;
491 }
492
493 template<class T>
494 void Packet::Payload::Read(T &dst, size_t off) const noexcept {
495         if ((length - off) < sizeof(T)) {
496                 // dismiss out of bounds read
497                 return;
498         }
499         dst = *reinterpret_cast<T *>(&data[off]);
500 }
501
502 void Packet::Payload::WriteString(const string &src, size_t off, size_t maxlen) noexcept {
503         uint8_t *dst = &data[off];
504         size_t len = min(maxlen, length - off);
505         if (src.size() < len) {
506                 memset(dst, '\0', len);
507                 memcpy(dst, src.c_str(), src.size());
508         } else {
509                 memcpy(dst, src.c_str(), len);
510         }
511 }
512
513 void Packet::Payload::ReadString(string &dst, size_t off, size_t maxlen) const noexcept {
514         size_t len = min(maxlen, length - off);
515         dst.clear();
516         dst.reserve(len);
517         for (size_t i = 0; i < len && data[off + i] != '\0'; ++i) {
518                 dst.push_back(data[off + i]);
519         }
520 }
521
522
523 void Packet::Login::WritePlayerName(const string &name) noexcept {
524         WriteString(name, 0, 32);
525 }
526
527 void Packet::Login::ReadPlayerName(string &name) const noexcept {
528         ReadString(name, 0, 32);
529 }
530
531 void Packet::Join::WritePlayer(const Entity &player) noexcept {
532         Write(player.ID(), 0);
533         Write(player.ChunkCoords(), 4);
534         Write(player.Position(), 16);
535         Write(player.Velocity(), 28);
536         Write(player.Orientation(), 40);
537         Write(player.AngularVelocity(), 56);
538 }
539
540 void Packet::Join::ReadPlayerID(uint32_t &id) const noexcept {
541         Read(id, 0);
542 }
543
544 void Packet::Join::ReadPlayer(Entity &player) const noexcept {
545         glm::ivec3 chunk_coords(0);
546         glm::vec3 pos;
547         glm::vec3 vel;
548         glm::quat rot;
549         glm::vec3 ang;
550
551         Read(chunk_coords, 4);
552         Read(pos, 16);
553         Read(vel, 28);
554         Read(rot, 40);
555         Read(ang, 56);
556
557         player.Position(chunk_coords, pos);
558         player.Velocity(vel);
559         player.Orientation(rot);
560         player.AngularVelocity(ang);
561 }
562
563 void Packet::Join::WriteWorldName(const string &name) noexcept {
564         WriteString(name, 68, 32);
565 }
566
567 void Packet::Join::ReadWorldName(string &name) const noexcept {
568         ReadString(name, 68, 32);
569 }
570
571 void Packet::PlayerUpdate::WritePlayer(const Entity &player) noexcept {
572         Write(player.ChunkCoords(), 0);
573         Write(player.Position(), 12);
574         Write(player.Velocity(), 24);
575         Write(player.Orientation(), 36);
576         Write(player.AngularVelocity(), 52);
577 }
578
579 void Packet::PlayerUpdate::ReadPlayer(Entity &player) const noexcept {
580         glm::ivec3 chunk_coords(0);
581         glm::vec3 pos;
582         glm::vec3 vel;
583         glm::quat rot;
584         glm::vec3 ang;
585
586         Read(chunk_coords, 0);
587         Read(pos, 12);
588         Read(vel, 24);
589         Read(rot, 36);
590         Read(ang, 52);
591
592         player.Position(chunk_coords, pos);
593         player.Velocity(vel);
594         player.Orientation(rot);
595         player.AngularVelocity(ang);
596 }
597
598 void Packet::SpawnEntity::WriteEntity(const Entity &e) noexcept {
599         Write(e.ID(), 0);
600         if (e.GetModel()) {
601                 Write(e.GetModel().GetModel().ID(), 4);
602         } else {
603                 Write(uint32_t(0), 4);
604         }
605         Write(e.ChunkCoords(), 8);
606         Write(e.Position(), 20);
607         Write(e.Velocity(), 32);
608         Write(e.Orientation(), 44);
609         Write(e.AngularVelocity(), 60);
610         Write(e.Bounds(), 72);
611         uint32_t flags = 0;
612         if (e.WorldCollidable()) {
613                 flags |= 1;
614         }
615         Write(flags, 96);
616         WriteString(e.Name(), 100, 32);
617 }
618
619 void Packet::SpawnEntity::ReadEntityID(uint32_t &id) const noexcept {
620         Read(id, 0);
621 }
622
623 void Packet::SpawnEntity::ReadSkeletonID(uint32_t &id) const noexcept {
624         Read(id, 4);
625 }
626
627 void Packet::SpawnEntity::ReadEntity(Entity &e) const noexcept {
628         glm::ivec3 chunk_coords(0);
629         glm::vec3 pos;
630         glm::vec3 vel;
631         glm::quat rot;
632         glm::vec3 ang;
633         AABB bounds;
634         uint32_t flags = 0;
635         string name;
636
637         Read(chunk_coords, 8);
638         Read(pos, 20);
639         Read(vel, 32);
640         Read(rot, 44);
641         Read(ang, 60);
642         Read(bounds, 72);
643         Read(flags, 96);
644         ReadString(name, 100, 32);
645
646         e.Position(chunk_coords, pos);
647         e.Velocity(vel);
648         e.Orientation(rot);
649         e.AngularVelocity(ang);
650         e.Bounds(bounds);
651         e.WorldCollidable(flags & 1);
652         e.Name(name);
653 }
654
655 void Packet::DespawnEntity::WriteEntityID(uint32_t id) noexcept {
656         Write(id, 0);
657 }
658
659 void Packet::DespawnEntity::ReadEntityID(uint32_t &id) const noexcept {
660         Read(id, 0);
661 }
662
663 void Packet::EntityUpdate::WriteEntityCount(uint32_t count) noexcept {
664         Write(count, 0);
665 }
666
667 void Packet::EntityUpdate::ReadEntityCount(uint32_t &count) const noexcept {
668         Read(count, 0);
669 }
670
671 void Packet::EntityUpdate::WriteEntity(const Entity &entity, uint32_t num) noexcept {
672         uint32_t off = 4 + (num * 64);
673
674         Write(entity.ID(), off);
675         Write(entity.ChunkCoords(), off + 4);
676         Write(entity.Position(), off + 16);
677         Write(entity.Velocity(), off + 28);
678         Write(entity.Orientation(), off + 40);
679         Write(entity.AngularVelocity(), off + 56);
680 }
681
682 void Packet::EntityUpdate::ReadEntityID(uint32_t &id, uint32_t num) const noexcept {
683         Read(id, 4 + (num * 64));
684 }
685
686 void Packet::EntityUpdate::ReadEntity(Entity &entity, uint32_t num) const noexcept {
687         uint32_t off = 4 + (num * 64);
688
689         glm::ivec3 chunk_coords(0);
690         glm::vec3 pos;
691         glm::vec3 vel;
692         glm::quat rot;
693         glm::vec3 ang;
694
695         Read(chunk_coords, off + 4);
696         Read(pos, off + 16);
697         Read(vel, off + 28);
698         Read(rot, off + 40);
699         Read(ang, off + 56);
700
701         entity.Position(chunk_coords, pos);
702         entity.Velocity(vel);
703         entity.Orientation(rot);
704         entity.AngularVelocity(ang);
705 }
706
707
708 void ConnectionHandler::Handle(const UDPpacket &udp_pack) {
709         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
710         switch (pack.Type()) {
711                 case Packet::Ping::TYPE:
712                         On(Packet::As<Packet::Ping>(udp_pack));
713                         break;
714                 case Packet::Login::TYPE:
715                         On(Packet::As<Packet::Login>(udp_pack));
716                         break;
717                 case Packet::Join::TYPE:
718                         On(Packet::As<Packet::Join>(udp_pack));
719                         break;
720                 case Packet::Part::TYPE:
721                         On(Packet::As<Packet::Part>(udp_pack));
722                         break;
723                 case Packet::PlayerUpdate::TYPE:
724                         On(Packet::As<Packet::PlayerUpdate>(udp_pack));
725                         break;
726                 case Packet::SpawnEntity::TYPE:
727                         On(Packet::As<Packet::SpawnEntity>(udp_pack));
728                         break;
729                 case Packet::DespawnEntity::TYPE:
730                         On(Packet::As<Packet::DespawnEntity>(udp_pack));
731                         break;
732                 case Packet::EntityUpdate::TYPE:
733                         On(Packet::As<Packet::EntityUpdate>(udp_pack));
734                         break;
735                 default:
736                         // drop unknown or unhandled packets
737                         break;
738         }
739 }
740
741
742 Server::Server(const Config &conf, World &world)
743 : serv_sock(nullptr)
744 , serv_pack{ -1, nullptr, 0 }
745 , clients()
746 , world(world) {
747         serv_sock = SDLNet_UDP_Open(conf.port);
748         if (!serv_sock) {
749                 throw NetError("SDLNet_UDP_Open");
750         }
751
752         serv_pack.data = new Uint8[sizeof(Packet)];
753         serv_pack.maxlen = sizeof(Packet);
754 }
755
756 Server::~Server() {
757         delete[] serv_pack.data;
758         SDLNet_UDP_Close(serv_sock);
759 }
760
761
762 void Server::Handle() {
763         int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
764         while (result > 0) {
765                 HandlePacket(serv_pack);
766                 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
767         }
768         if (result == -1) {
769                 // a boo boo happened
770                 throw NetError("SDLNet_UDP_Recv");
771         }
772 }
773
774 void Server::HandlePacket(const UDPpacket &udp_pack) {
775         if (udp_pack.len < int(sizeof(Packet::Header))) {
776                 // packet too small, drop
777                 return;
778         }
779         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
780         if (pack.header.tag != Packet::TAG) {
781                 // mistagged packet, drop
782                 return;
783         }
784
785         ClientConnection &client = GetClient(udp_pack.address);
786         client.GetConnection().Received(udp_pack);
787 }
788
789 ClientConnection &Server::GetClient(const IPaddress &addr) {
790         for (ClientConnection &client : clients) {
791                 if (client.Matches(addr)) {
792                         return client;
793                 }
794         }
795         clients.emplace_back(*this, addr);
796         return clients.back();
797 }
798
799 void Server::Update(int dt) {
800         for (list<ClientConnection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
801                 client->Update(dt);
802                 if (client->Disconnected()) {
803                         client = clients.erase(client);
804                 } else {
805                         ++client;
806                 }
807         }
808 }
809
810 }