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