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