]> git.localhorst.tv Git - blank.git/blob - src/server/net.cpp
split input handling
[blank.git] / src / server / net.cpp
1 #include "ClientConnection.hpp"
2 #include "ChunkTransmitter.hpp"
3 #include "Server.hpp"
4
5 #include "../app/init.hpp"
6 #include "../model/CompositeModel.hpp"
7 #include "../world/ChunkIndex.hpp"
8 #include "../world/Entity.hpp"
9 #include "../world/World.hpp"
10
11 #include <iostream>
12 #include <zlib.h>
13
14 using namespace std;
15
16
17 namespace blank {
18 namespace server {
19
20 ChunkTransmitter::ChunkTransmitter(ClientConnection &conn)
21 : conn(conn)
22 , current(nullptr)
23 , buffer_size(Chunk::BlockSize() + 10)
24 , buffer(new uint8_t[buffer_size])
25 , buffer_len(0)
26 , packet_len(Packet::ChunkData::MAX_DATA_LEN)
27 , cursor(0)
28 , num_packets(0)
29 , begin_packet(-1)
30 , data_packets()
31 , confirm_wait(0)
32 , trans_id(0)
33 , compressed(false) {
34
35 }
36
37 ChunkTransmitter::~ChunkTransmitter() {
38         Abort();
39 }
40
41 bool ChunkTransmitter::Idle() const noexcept {
42         return !Transmitting() && !Waiting();
43 }
44
45 bool ChunkTransmitter::Transmitting() const noexcept {
46         return cursor < num_packets;
47 }
48
49 void ChunkTransmitter::Transmit() {
50         if (cursor < num_packets) {
51                 SendData(cursor);
52                 ++cursor;
53         }
54 }
55
56 bool ChunkTransmitter::Waiting() const noexcept {
57         return confirm_wait > 0;
58 }
59
60 void ChunkTransmitter::Ack(uint16_t seq) {
61         if (!Waiting()) {
62                 return;
63         }
64         if (seq == begin_packet) {
65                 begin_packet = -1;
66                 --confirm_wait;
67                 if (Idle()) {
68                         Release();
69                 }
70                 return;
71         }
72         for (int i = 0, end = data_packets.size(); i < end; ++i) {
73                 if (seq == data_packets[i]) {
74                         data_packets[i] = -1;
75                         --confirm_wait;
76                         if (Idle()) {
77                                 Release();
78                         }
79                         return;
80                 }
81         }
82 }
83
84 void ChunkTransmitter::Nack(uint16_t seq) {
85         if (!Waiting()) {
86                 return;
87         }
88         if (seq == begin_packet) {
89                 SendBegin();
90                 return;
91         }
92         for (size_t i = 0, end = data_packets.size(); i < end; ++i) {
93                 if (seq == data_packets[i]) {
94                         SendData(i);
95                         return;
96                 }
97         }
98 }
99
100 void ChunkTransmitter::Abort() {
101         if (!current) return;
102
103         Release();
104
105         begin_packet = -1;
106         data_packets.clear();
107         confirm_wait = 0;
108 }
109
110 void ChunkTransmitter::Send(Chunk &chunk) {
111         // abort current chunk, if any
112         Abort();
113
114         current = &chunk;
115         current->Ref();
116
117         // load new chunk data
118         compressed = true;
119         buffer_len = buffer_size;
120         if (compress(buffer.get(), &buffer_len, reinterpret_cast<const Bytef *>(chunk.BlockData()), Chunk::BlockSize()) != Z_OK) {
121                 // compression failed, send it uncompressed
122                 buffer_len = Chunk::BlockSize();
123                 memcpy(buffer.get(), chunk.BlockData(), buffer_len);
124                 compressed = false;
125         }
126         cursor = 0;
127         num_packets = (buffer_len / packet_len) + (buffer_len % packet_len != 0);
128         data_packets.resize(num_packets, -1);
129
130         ++trans_id;
131         SendBegin();
132 }
133
134 void ChunkTransmitter::SendBegin() {
135         uint32_t flags = compressed;
136         auto pack = conn.Prepare<Packet::ChunkBegin>();
137         pack.WriteTransmissionId(trans_id);
138         pack.WriteFlags(flags);
139         pack.WriteChunkCoords(current->Position());
140         pack.WriteDataSize(buffer_len);
141         if (begin_packet == -1) {
142                 ++confirm_wait;
143         }
144         begin_packet = conn.Send();
145 }
146
147 void ChunkTransmitter::SendData(size_t i) {
148         int pos = i * packet_len;
149         int len = min(packet_len, buffer_len - pos);
150         const uint8_t *data = &buffer[pos];
151
152         auto pack = conn.Prepare<Packet::ChunkData>();
153         pack.WriteTransmissionId(trans_id);
154         pack.WriteDataOffset(pos);
155         pack.WriteDataSize(len);
156         pack.WriteData(data, len);
157
158         if (data_packets[i] == -1) {
159                 ++confirm_wait;
160         }
161         data_packets[i] = conn.Send();
162 }
163
164 void ChunkTransmitter::Release() {
165         if (current) {
166                 current->UnRef();
167                 current = nullptr;
168         }
169 }
170
171
172 ClientConnection::ClientConnection(Server &server, const IPaddress &addr)
173 : server(server)
174 , conn(addr)
175 , player(nullptr)
176 , player_model(nullptr)
177 , spawns()
178 , confirm_wait(0)
179 , entity_updates()
180 , player_update_state()
181 , player_update_pack(0)
182 , player_update_timer(1500)
183 , transmitter(*this)
184 , chunk_queue()
185 , old_base() {
186         conn.SetHandler(this);
187 }
188
189 ClientConnection::~ClientConnection() {
190         DetachPlayer();
191 }
192
193 void ClientConnection::Update(int dt) {
194         conn.Update(dt);
195         if (Disconnected()) {
196                 return;
197         }
198         if (HasPlayer()) {
199                 // sync entities
200                 auto global_iter = server.GetWorld().Entities().begin();
201                 auto global_end = server.GetWorld().Entities().end();
202                 auto local_iter = spawns.begin();
203                 auto local_end = spawns.end();
204
205                 while (global_iter != global_end && local_iter != local_end) {
206                         if (global_iter->ID() == local_iter->entity->ID()) {
207                                 // they're the same
208                                 if (CanDespawn(*global_iter)) {
209                                         SendDespawn(*local_iter);
210                                 } else {
211                                         // update
212                                         QueueUpdate(*local_iter);
213                                 }
214                                 ++global_iter;
215                                 ++local_iter;
216                         } else if (global_iter->ID() < local_iter->entity->ID()) {
217                                 // global entity was inserted
218                                 if (CanSpawn(*global_iter)) {
219                                         auto spawned = spawns.emplace(local_iter, *global_iter);
220                                         SendSpawn(*spawned);
221                                 }
222                                 ++global_iter;
223                         } else {
224                                 // global entity was removed
225                                 SendDespawn(*local_iter);
226                                 ++local_iter;
227                         }
228                 }
229
230                 // leftover spawns
231                 while (global_iter != global_end) {
232                         if (CanSpawn(*global_iter)) {
233                                 spawns.emplace_back(*global_iter);
234                                 SendSpawn(spawns.back());
235                         }
236                         ++global_iter;
237                 }
238
239                 // leftover despawns
240                 while (local_iter != local_end) {
241                         SendDespawn(*local_iter);
242                         ++local_iter;
243                 }
244                 SendUpdates();
245
246                 CheckPlayerFix();
247                 CheckChunkQueue();
248         }
249         if (conn.ShouldPing()) {
250                 conn.SendPing(server.GetPacket(), server.GetSocket());
251         }
252 }
253
254 ClientConnection::SpawnStatus::SpawnStatus(Entity &e)
255 : entity(&e)
256 , spawn_pack(-1)
257 , despawn_pack(-1) {
258         entity->Ref();
259 }
260
261 ClientConnection::SpawnStatus::~SpawnStatus() {
262         entity->UnRef();
263 }
264
265 bool ClientConnection::CanSpawn(const Entity &e) const noexcept {
266         return
267                 &e != &PlayerEntity() &&
268                 !e.Dead() &&
269                 manhattan_radius(e.ChunkCoords() - PlayerEntity().ChunkCoords()) < 7;
270 }
271
272 bool ClientConnection::CanDespawn(const Entity &e) const noexcept {
273         return
274                 e.Dead() ||
275                 manhattan_radius(e.ChunkCoords() - PlayerEntity().ChunkCoords()) > 7;
276 }
277
278 uint16_t ClientConnection::Send() {
279         return conn.Send(server.GetPacket(), server.GetSocket());
280 }
281
282 uint16_t ClientConnection::Send(size_t len) {
283         server.GetPacket().len = len;
284         return Send();
285 }
286
287 void ClientConnection::SendSpawn(SpawnStatus &status) {
288         // don't double spawn
289         if (status.spawn_pack != -1) return;
290
291         auto pack = Prepare<Packet::SpawnEntity>();
292         pack.WriteEntity(*status.entity);
293         status.spawn_pack = Send();
294         ++confirm_wait;
295 }
296
297 void ClientConnection::SendDespawn(SpawnStatus &status) {
298         // don't double despawn
299         if (status.despawn_pack != -1) return;
300
301         auto pack = Prepare<Packet::DespawnEntity>();
302         pack.WriteEntityID(status.entity->ID());
303         status.despawn_pack = Send();
304         ++confirm_wait;
305 }
306
307 void ClientConnection::QueueUpdate(SpawnStatus &status) {
308         // don't send updates while spawn not ack'd or despawn sent
309         if (status.spawn_pack == -1 && status.despawn_pack == -1) {
310                 entity_updates.push_back(&status);
311         }
312 }
313
314 void ClientConnection::SendUpdates() {
315         auto pack = Prepare<Packet::EntityUpdate>();
316         int entity_pos = 0;
317         for (SpawnStatus *status : entity_updates) {
318                 pack.WriteEntity(*status->entity, entity_pos);
319                 ++entity_pos;
320                 if (entity_pos == Packet::EntityUpdate::MAX_ENTITIES) {
321                         pack.WriteEntityCount(entity_pos);
322                         Send(Packet::EntityUpdate::GetSize(entity_pos));
323                         pack = Prepare<Packet::EntityUpdate>();
324                         entity_pos = 0;
325                 }
326         }
327         if (entity_pos > 0) {
328                 pack.WriteEntityCount(entity_pos);
329                 Send(Packet::EntityUpdate::GetSize(entity_pos));
330         }
331         entity_updates.clear();
332 }
333
334 void ClientConnection::CheckPlayerFix() {
335         // player_update_state's position holds the client's most recent prediction
336         glm::vec3 diff = player_update_state.Diff(PlayerEntity().GetState());
337         float dist_squared = dot(diff, diff);
338
339         // if client's prediction is off by more than 1cm, send
340         // our (authoritative) state back so it can fix it
341         constexpr float fix_thresh = 0.0001f;
342
343         if (dist_squared > fix_thresh) {
344                 auto pack = Prepare<Packet::PlayerCorrection>();
345                 pack.WritePacketSeq(player_update_pack);
346                 pack.WritePlayer(PlayerEntity());
347                 Send();
348         }
349 }
350
351 void ClientConnection::CheckChunkQueue() {
352         if (PlayerChunks().Base() != old_base) {
353                 Chunk::Pos begin = PlayerChunks().CoordsBegin();
354                 Chunk::Pos end = PlayerChunks().CoordsEnd();
355                 for (Chunk::Pos pos = begin; pos.z < end.z; ++pos.z) {
356                         for (pos.y = begin.y; pos.y < end.y; ++pos.y) {
357                                 for (pos.x = begin.x; pos.x < end.x; ++pos.x) {
358                                         if (manhattan_radius(pos - old_base) > PlayerChunks().Extent()) {
359                                                 chunk_queue.push_back(pos);
360                                         }
361                                 }
362                         }
363                 }
364                 old_base = PlayerChunks().Base();
365         }
366         if (transmitter.Transmitting()) {
367                 transmitter.Transmit();
368                 return;
369         }
370         if (transmitter.Idle()) {
371                 int count = 0;
372                 constexpr int max = 64;
373                 while (count < max && !chunk_queue.empty()) {
374                         Chunk::Pos pos = chunk_queue.front();
375                         chunk_queue.pop_front();
376                         if (PlayerChunks().InRange(pos)) {
377                                 Chunk *chunk = PlayerChunks().Get(pos);
378                                 if (chunk) {
379                                         transmitter.Send(*chunk);
380                                         return;
381                                 } else {
382                                         chunk_queue.push_back(pos);
383                                 }
384                                 ++count;
385                         }
386                 }
387         }
388 }
389
390 void ClientConnection::AttachPlayer(Player &new_player) {
391         DetachPlayer();
392         player = &new_player;
393         PlayerEntity().Ref();
394
395         old_base = PlayerChunks().Base();
396         Chunk::Pos begin = PlayerChunks().CoordsBegin();
397         Chunk::Pos end = PlayerChunks().CoordsEnd();
398         for (Chunk::Pos pos = begin; pos.z < end.z; ++pos.z) {
399                 for (pos.y = begin.y; pos.y < end.y; ++pos.y) {
400                         for (pos.x = begin.x; pos.x < end.x; ++pos.x) {
401                                 chunk_queue.push_back(pos);
402                         }
403                 }
404         }
405         if (HasPlayerModel()) {
406                 GetPlayerModel().Instantiate(PlayerEntity().GetModel());
407         }
408
409         cout << "player \"" << player->Name() << "\" joined" << endl;
410 }
411
412 void ClientConnection::DetachPlayer() {
413         if (!HasPlayer()) return;
414         cout << "player \"" << player->Name() << "\" left" << endl;
415         player->GetEntity().Kill();
416         player->GetEntity().UnRef();
417         player = nullptr;
418         transmitter.Abort();
419         chunk_queue.clear();
420 }
421
422 void ClientConnection::SetPlayerModel(const CompositeModel &m) noexcept {
423         player_model = &m;
424         if (HasPlayer()) {
425                 m.Instantiate(PlayerEntity().GetModel());
426         }
427 }
428
429 bool ClientConnection::HasPlayerModel() const noexcept {
430         return player_model;
431 }
432
433 const CompositeModel &ClientConnection::GetPlayerModel() const noexcept {
434         return *player_model;
435 }
436
437 void ClientConnection::OnPacketReceived(uint16_t seq) {
438         if (transmitter.Waiting()) {
439                 transmitter.Ack(seq);
440         }
441         if (!confirm_wait) return;
442         for (auto iter = spawns.begin(), end = spawns.end(); iter != end; ++iter) {
443                 if (seq == iter->spawn_pack) {
444                         iter->spawn_pack = -1;
445                         --confirm_wait;
446                         return;
447                 }
448                 if (seq == iter->despawn_pack) {
449                         spawns.erase(iter);
450                         --confirm_wait;
451                         return;
452                 }
453         }
454 }
455
456 void ClientConnection::OnPacketLost(uint16_t seq) {
457         if (transmitter.Waiting()) {
458                 transmitter.Nack(seq);
459         }
460         if (!confirm_wait) return;
461         for (SpawnStatus &status : spawns) {
462                 if (seq == status.spawn_pack) {
463                         status.spawn_pack = -1;
464                         --confirm_wait;
465                         SendSpawn(status);
466                         return;
467                 }
468                 if (seq == status.despawn_pack) {
469                         status.despawn_pack = -1;
470                         --confirm_wait;
471                         SendDespawn(status);
472                         return;
473                 }
474         }
475 }
476
477 void ClientConnection::On(const Packet::Login &pack) {
478         string name;
479         pack.ReadPlayerName(name);
480
481         Player *new_player = server.GetWorld().AddPlayer(name);
482
483         if (new_player) {
484                 // success!
485                 AttachPlayer(*new_player);
486                 cout << "accepted login from player \"" << name << '"' << endl;
487                 auto response = Prepare<Packet::Join>();
488                 response.WritePlayer(new_player->GetEntity());
489                 response.WriteWorldName(server.GetWorld().Name());
490                 Send();
491                 // set up update tracking
492                 player_update_state = new_player->GetEntity().GetState();
493                 player_update_pack = pack.Seq();
494                 player_update_timer.Reset();
495                 player_update_timer.Start();
496         } else {
497                 // aw no :(
498                 cout << "rejected login from player \"" << name << '"' << endl;
499                 Prepare<Packet::Part>();
500                 Send();
501                 conn.Close();
502         }
503 }
504
505 void ClientConnection::On(const Packet::Part &) {
506         conn.Close();
507 }
508
509 void ClientConnection::On(const Packet::PlayerUpdate &pack) {
510         if (!HasPlayer()) return;
511         int pack_diff = int16_t(pack.Seq()) - int16_t(player_update_pack);
512         bool overdue = player_update_timer.HitOnce();
513         player_update_timer.Reset();
514         if (pack_diff > 0 || overdue) {
515                 player_update_pack = pack.Seq();
516                 pack.ReadPlayerState(player_update_state);
517                 // accept velocity and orientation as "user input"
518                 PlayerEntity().Velocity(player_update_state.velocity);
519                 PlayerEntity().Orientation(player_update_state.orient);
520         }
521 }
522
523
524 Server::Server(const Config::Network &conf, World &world)
525 : serv_sock(nullptr)
526 , serv_pack{ -1, nullptr, 0 }
527 , clients()
528 , world(world)
529 , player_model(nullptr) {
530         serv_sock = SDLNet_UDP_Open(conf.port);
531         if (!serv_sock) {
532                 throw NetError("SDLNet_UDP_Open");
533         }
534
535         serv_pack.data = new Uint8[sizeof(Packet)];
536         serv_pack.maxlen = sizeof(Packet);
537 }
538
539 Server::~Server() {
540         delete[] serv_pack.data;
541         SDLNet_UDP_Close(serv_sock);
542 }
543
544
545 void Server::Handle() {
546         int result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
547         while (result > 0) {
548                 HandlePacket(serv_pack);
549                 result = SDLNet_UDP_Recv(serv_sock, &serv_pack);
550         }
551         if (result == -1) {
552                 // a boo boo happened
553                 throw NetError("SDLNet_UDP_Recv");
554         }
555 }
556
557 void Server::HandlePacket(const UDPpacket &udp_pack) {
558         if (udp_pack.len < int(sizeof(Packet::Header))) {
559                 // packet too small, drop
560                 return;
561         }
562         const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
563         if (pack.header.tag != Packet::TAG) {
564                 // mistagged packet, drop
565                 return;
566         }
567
568         ClientConnection &client = GetClient(udp_pack.address);
569         client.GetConnection().Received(udp_pack);
570 }
571
572 ClientConnection &Server::GetClient(const IPaddress &addr) {
573         for (ClientConnection &client : clients) {
574                 if (client.Matches(addr)) {
575                         return client;
576                 }
577         }
578         clients.emplace_back(*this, addr);
579         if (HasPlayerModel()) {
580                 clients.back().SetPlayerModel(GetPlayerModel());
581         }
582         return clients.back();
583 }
584
585 void Server::Update(int dt) {
586         for (list<ClientConnection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
587                 client->Update(dt);
588                 if (client->Disconnected()) {
589                         client = clients.erase(client);
590                 } else {
591                         ++client;
592                 }
593         }
594 }
595
596 void Server::SetPlayerModel(const CompositeModel &m) noexcept {
597         player_model = &m;
598         for (ClientConnection &client : clients) {
599                 client.SetPlayerModel(m);
600         }
601 }
602
603 bool Server::HasPlayerModel() const noexcept {
604         return player_model;
605 }
606
607 const CompositeModel &Server::GetPlayerModel() const noexcept {
608         return *player_model;
609 }
610
611 }
612 }