OpenTTD Source 20260107-master-g88a467db19
network_server.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "../stdafx.h"
11#include "../strings_func.h"
13#include "network_admin.h"
14#include "network_server.h"
15#include "network_udp.h"
16#include "network_base.h"
17#include "../console_func.h"
18#include "../company_base.h"
19#include "../command_func.h"
20#include "../saveload/saveload.h"
21#include "../saveload/saveload_filter.h"
22#include "../station_base.h"
23#include "../genworld.h"
24#include "../company_func.h"
25#include "../company_gui.h"
26#include "../company_cmd.h"
27#include "../roadveh.h"
28#include "../order_backup.h"
29#include "../core/pool_func.hpp"
30#include "../core/random_func.hpp"
31#include "../company_cmd.h"
32#include "../rev.h"
33#include "../timer/timer.h"
34#include "../timer/timer_game_calendar.h"
35#include "../timer/timer_game_economy.h"
36#include "../timer/timer_game_realtime.h"
37#include <mutex>
38#include <condition_variable>
39
40#include "table/strings.h"
41
42#include "../safeguards.h"
43
44
45/* This file handles all the server-commands */
46
50
52static_assert(NetworkClientSocketPool::MAX_SIZE > MAX_CLIENTS);
53
56INSTANTIATE_POOL_METHODS(NetworkClientSocket)
57
60
64
65
69 std::unique_ptr<Packet> current;
70 size_t total_size;
71 std::deque<std::unique_ptr<Packet>> packets;
72 std::mutex mutex;
73 std::condition_variable exit_sig;
74
79 PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(nullptr), cs(cs), total_size(0)
80 {
81 }
82
84 ~PacketWriter() override
85 {
86 std::unique_lock<std::mutex> lock(this->mutex);
87
88 while (this->cs != nullptr) this->exit_sig.wait(lock);
89
90 /* This must all wait until the Destroy function is called. */
91
92 this->packets.clear();
93 this->current = nullptr;
94 }
95
106 void Destroy()
107 {
108 std::unique_lock<std::mutex> lock(this->mutex);
109
110 this->cs = nullptr;
111
112 this->exit_sig.notify_all();
113 lock.unlock();
114
115 /* Make sure the saving is completely cancelled. Yes,
116 * we need to handle the save finish as well as the
117 * next connection might just be requesting a map. */
118 WaitTillSaved();
119 }
120
127 {
128 /* Unsafe check for the queue being empty or not. */
129 if (this->packets.empty()) return false;
130
131 std::lock_guard<std::mutex> lock(this->mutex);
132
133 while (!this->packets.empty()) {
134 bool last_packet = this->packets.front()->GetPacketType() == PACKET_SERVER_MAP_DONE;
135 this->cs->SendPacket(std::move(this->packets.front()));
136 this->packets.pop_front();
137
138 if (last_packet) return true;
139 }
140
141 return false;
142 }
143
144 void Write(uint8_t *buf, size_t size) override
145 {
146 std::lock_guard<std::mutex> lock(this->mutex);
147
148 /* We want to abort the saving when the socket is closed. */
149 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
150
151 if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
152
153 std::span<const uint8_t> to_write(buf, size);
154 while (!to_write.empty()) {
155 to_write = this->current->Send_bytes(to_write);
156
157 if (!this->current->CanWriteToPacket(1)) {
158 this->packets.push_back(std::move(this->current));
159 if (!to_write.empty()) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
160 }
161 }
162
163 this->total_size += size;
164 }
165
166 void Finish() override
167 {
168 std::lock_guard<std::mutex> lock(this->mutex);
169
170 /* We want to abort the saving when the socket is closed. */
171 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
172
173 /* Make sure the last packet is flushed. */
174 if (this->current != nullptr) this->packets.push_back(std::move(this->current));
175
176 /* Add a packet stating that this is the end to the queue. */
177 this->packets.push_back(std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DONE));
178
179 /* Fast-track the size to the client. */
180 auto p = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_SIZE);
181 p->Send_uint32((uint32_t)this->total_size);
182 this->packets.push_front(std::move(p));
183 }
184};
185
186
194{
197
198 Debug(net, 9, "client[{}] status = INACTIVE", this->client_id);
199
200 /* The Socket and Info pools need to be the same in size. After all,
201 * each Socket will be associated with at most one Info object. As
202 * such if the Socket was allocated the Info object can as well. */
204}
205
210{
211 delete this->GetInfo();
212
215
216 if (this->savegame != nullptr) {
217 this->savegame->Destroy();
218 this->savegame = nullptr;
219 }
220
222}
223
225{
226 /* Only allow receiving when we have some buffer free; this value
227 * can go negative, but eventually it will become positive again. */
228 if (this->receive_limit <= 0) return nullptr;
229
230 /* We can receive a packet, so try that and if needed account for
231 * the amount of received data. */
232 std::unique_ptr<Packet> p = this->NetworkTCPSocketHandler::ReceivePacket();
233 if (p != nullptr) this->receive_limit -= p->Size();
234 return p;
235}
236
238{
240 /*
241 * Sending a message just before leaving the game calls cs->SendPackets.
242 * This might invoke this function, which means that when we close the
243 * connection after cs->SendPackets we will close an already closed
244 * connection. This handles that case gracefully without having to make
245 * that code any more complex or more aware of the validity of the socket.
246 */
247 if (this->IsPendingDeletion() || this->sock == INVALID_SOCKET) return status;
248
250 /* We did not receive a leave message from this client... */
251 std::string client_name = this->GetClientName();
252
253 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
254
255 /* Inform other clients of this... strange leaving ;) */
257 if (new_cs->status >= STATUS_AUTHORIZED && this != new_cs) {
258 new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
259 }
260 }
261 }
262
263 /* If we were transferring a map to this client, stop the savegame creation
264 * process and queue the next client to receive the map. */
265 if (this->status == STATUS_MAP) {
266 /* Ensure the saving of the game is stopped too. */
267 this->savegame->Destroy();
268 this->savegame = nullptr;
269
270 this->CheckNextClientToSendMap(this);
271 }
272
273 NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
274 Debug(net, 3, "[{}] Client #{} closed connection", ServerNetworkGameSocketHandler::GetName(), this->client_id);
275
276 /* We just lost one client :( */
277 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
278 extern uint8_t _network_clients_connected;
280
281 this->SendPackets(true);
282
283 this->DeferDeletion();
284
285 return status;
286}
287
293{
294 extern uint8_t _network_clients_connected;
296
297 /* We can't go over the MAX_CLIENTS limit here. However, the
298 * pool must have place for all clients and ourself. */
301 return accept;
302}
303
306{
308 if (cs->writable) {
309 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
310 /* This client is in the middle of a map-send, call the function for that */
311 cs->SendMap();
312 }
313 }
314 }
315}
316
317static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
318
319/***********
320 * Sending functions
321 ************/
322
328{
329 Debug(net, 9, "client[{}] SendClientInfo(): client_id={}", this->client_id, ci->client_id);
330
331 if (ci->client_id != INVALID_CLIENT_ID) {
332 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CLIENT_INFO);
333 p->Send_uint32(ci->client_id);
334 p->Send_uint8 (ci->client_playas);
335 p->Send_string(ci->client_name);
336 p->Send_string(ci->public_key);
337
338 this->SendPacket(std::move(p));
339 }
341}
342
345{
346 Debug(net, 9, "client[{}] SendGameInfo()", this->client_id);
347
348 auto p = std::make_unique<Packet>(this, PACKET_SERVER_GAME_INFO, TCP_MTU);
350
351 this->SendPacket(std::move(p));
352
354}
355
362{
363 Debug(net, 9, "client[{}] SendError(): error={}", this->client_id, error);
364
365 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR);
366
367 p->Send_uint8(error);
368 if (!reason.empty()) p->Send_string(reason);
369 this->SendPacket(std::move(p));
370
371 StringID strid = GetNetworkErrorMsg(error);
372
373 /* Only send when the current client was in game */
374 if (this->status >= STATUS_AUTHORIZED) {
375 std::string client_name = this->GetClientName();
376
377 Debug(net, 1, "'{}' made an error and has been disconnected: {}", client_name, GetString(strid));
378
379 if (error == NETWORK_ERROR_KICKED && !reason.empty()) {
380 NetworkTextMessage(NETWORK_ACTION_KICKED, CC_DEFAULT, false, client_name, reason, strid);
381 } else {
382 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
383 }
384
386 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
387 /* Some errors we filter to a more general error. Clients don't have to know the real
388 * reason a joining failed. */
389 if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
390 error = NETWORK_ERROR_ILLEGAL_PACKET;
391 }
392 new_cs->SendErrorQuit(this->client_id, error);
393 }
394 }
395
397 } else {
398 Debug(net, 1, "Client {} made an error and has been disconnected: {}", this->client_id, GetString(strid));
399 }
400
401 /* The client made a mistake, so drop the connection now! */
403}
404
407{
408 Debug(net, 9, "client[{}] SendNewGRFCheck()", this->client_id);
409
410 /* Invalid packet when status is anything but STATUS_IDENTIFY. */
412
413 Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
415
416 if (_grfconfig.empty()) {
417 /* There are no NewGRFs, so they're welcome. */
418 return this->SendWelcome();
419 }
420
421 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
422
423 uint grf_count = std::ranges::count_if(_grfconfig, [](const auto &c){ return !c->flags.Test(GRFConfigFlag::Static); });
424 p->Send_uint8 (grf_count);
425
426 for (const auto &c : _grfconfig) {
427 if (!c->flags.Test(GRFConfigFlag::Static)) SerializeGRFIdentifier(*p, c->ident);
428 }
429
430 this->SendPacket(std::move(p));
432}
433
436{
437 Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
438
439 /* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
441
442 Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
443 this->status = STATUS_AUTH_GAME;
444
445 /* Reset 'lag' counters */
447
448 if (this->authentication_handler == nullptr) {
450 }
451
452 auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST);
453 this->authentication_handler->SendRequest(*p);
454
455 this->SendPacket(std::move(p));
457}
458
461{
462 Debug(net, 9, "client[{}] SendEnableEncryption()", this->client_id);
463
464 /* Invalid packet when status is anything but STATUS_AUTH_GAME. */
466
467 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ENABLE_ENCRYPTION);
468 this->authentication_handler->SendEnableEncryption(*p);
469 this->SendPacket(std::move(p));
471}
472
475{
476 Debug(net, 9, "client[{}] SendWelcome()", this->client_id);
477
478 /* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
480
481 Debug(net, 9, "client[{}] status = AUTHORIZED", this->client_id);
483
484 /* Reset 'lag' counters */
486
488
489 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WELCOME);
490 p->Send_uint32(this->client_id);
491 this->SendPacket(std::move(p));
492
493 /* Transmit info about all the active clients */
495 if (new_cs != this && new_cs->status >= STATUS_AUTHORIZED) {
496 this->SendClientInfo(new_cs->GetInfo());
497 }
498 }
499 /* Also send the info of the server */
501}
502
505{
506 Debug(net, 9, "client[{}] SendWait()", this->client_id);
507
508 int waiting = 1; // current player getting the map counts as 1
509
510 /* Count how many clients are waiting in the queue, in front of you! */
512 if (new_cs->status != STATUS_MAP_WAIT) continue;
513 if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
514 }
515
516 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WAIT);
517 p->Send_uint8(waiting);
518 this->SendPacket(std::move(p));
520}
521
522void ServerNetworkGameSocketHandler::CheckNextClientToSendMap(NetworkClientSocket *ignore_cs)
523{
524 Debug(net, 9, "client[{}] CheckNextClientToSendMap()", this->client_id);
525
526 /* Find the best candidate for joining, i.e. the first joiner. */
527 NetworkClientSocket *best = nullptr;
528 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
529 if (ignore_cs == new_cs) continue;
530
531 if (new_cs->status == STATUS_MAP_WAIT) {
532 if (best == nullptr || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) {
533 best = new_cs;
534 }
535 }
536 }
537
538 /* Is there someone else to join? */
539 if (best != nullptr) {
540 /* Let the first start joining. */
541 best->status = STATUS_AUTHORIZED;
542 best->SendMap();
543
544 /* And update the rest. */
545 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
546 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
547 }
548 }
549}
550
553{
554 if (this->status < STATUS_AUTHORIZED) {
555 /* Illegal call, return error and ignore the packet */
556 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
557 }
558
559 if (this->status == STATUS_AUTHORIZED) {
560 Debug(net, 9, "client[{}] SendMap(): first_packet", this->client_id);
561
562 WaitTillSaved();
563 this->savegame = std::make_shared<PacketWriter>(this);
564
565 /* Now send the _frame_counter and how many packets are coming */
566 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MAP_BEGIN);
567 p->Send_uint32(_frame_counter);
568 this->SendPacket(std::move(p));
569
571 Debug(net, 9, "client[{}] status = MAP", this->client_id);
572 this->status = STATUS_MAP;
573 /* Mark the start of download */
576
577 /* Make a dump of the current game */
578 if (SaveWithFilter(this->savegame, true) != SL_OK) UserError("network savedump failed");
579 }
580
581 if (this->status == STATUS_MAP) {
582 bool last_packet = this->savegame->TransferToNetworkQueue();
583 if (last_packet) {
584 Debug(net, 9, "client[{}] SendMap(): last_packet", this->client_id);
585
586 /* Done reading, make sure saving is done as well */
587 this->savegame->Destroy();
588 this->savegame = nullptr;
589
590 /* Set the status to DONE_MAP, no we will wait for the client
591 * to send it is ready (maybe that happens like never ;)) */
592 Debug(net, 9, "client[{}] status = DONE_MAP", this->client_id);
593 this->status = STATUS_DONE_MAP;
594
595 this->CheckNextClientToSendMap();
596 }
597 }
599}
600
606{
607 Debug(net, 9, "client[{}] SendJoin(): client_id={}", this->client_id, client_id);
608
609 auto p = std::make_unique<Packet>(this, PACKET_SERVER_JOIN);
610
611 p->Send_uint32(client_id);
612
613 this->SendPacket(std::move(p));
615}
616
619{
620 auto p = std::make_unique<Packet>(this, PACKET_SERVER_FRAME);
621 p->Send_uint32(_frame_counter);
622 p->Send_uint32(_frame_counter_max);
623#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
624 p->Send_uint32(_sync_seed_1);
625#ifdef NETWORK_SEND_DOUBLE_SEED
626 p->Send_uint32(_sync_seed_2);
627#endif
628#endif
629
630 /* If token equals 0, we need to make a new token and send that. */
631 if (this->last_token == 0) {
632 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
633 p->Send_uint8(this->last_token);
634 }
635
636 this->SendPacket(std::move(p));
638}
639
642{
643 Debug(net, 9, "client[{}] SendSync(), frame_counter={}, sync_seed_1={}", this->client_id, _frame_counter, _sync_seed_1);
644
645 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SYNC);
646 p->Send_uint32(_frame_counter);
647 p->Send_uint32(_sync_seed_1);
648
649#ifdef NETWORK_SEND_DOUBLE_SEED
650 p->Send_uint32(_sync_seed_2);
651#endif
652 this->SendPacket(std::move(p));
654}
655
661{
662 Debug(net, 9, "client[{}] SendCommand(): cmd={}", this->client_id, cp.cmd);
663
664 auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMMAND);
665
667 p->Send_uint32(cp.frame);
668 p->Send_bool (cp.my_cmd);
669
670 this->SendPacket(std::move(p));
672}
673
682NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, std::string_view msg, int64_t data)
683{
684 Debug(net, 9, "client[{}] SendChat(): action={}, client_id={}, self_send={}", this->client_id, action, client_id, self_send);
685
687
688 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHAT);
689
690 p->Send_uint8 (action);
691 p->Send_uint32(client_id);
692 p->Send_bool (self_send);
693 p->Send_string(msg);
694 p->Send_uint64(data);
695
696 this->SendPacket(std::move(p));
698}
699
707NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
708{
709 Debug(net, 9, "client[{}] SendExternalChat(): source={}", this->client_id, source);
710
712
713 auto p = std::make_unique<Packet>(this, PACKET_SERVER_EXTERNAL_CHAT);
714
715 p->Send_string(source);
716 p->Send_uint16(colour);
717 p->Send_string(user);
718 p->Send_string(msg);
719
720 this->SendPacket(std::move(p));
722}
723
730{
731 Debug(net, 9, "client[{}] SendErrorQuit(): client_id={}, errorno={}", this->client_id, client_id, errorno);
732
733 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR_QUIT);
734
735 p->Send_uint32(client_id);
736 p->Send_uint8 (errorno);
737
738 this->SendPacket(std::move(p));
740}
741
747{
748 Debug(net, 9, "client[{}] SendQuit(): client_id={}", this->client_id, client_id);
749
750 auto p = std::make_unique<Packet>(this, PACKET_SERVER_QUIT);
751
752 p->Send_uint32(client_id);
753
754 this->SendPacket(std::move(p));
756}
757
760{
761 Debug(net, 9, "client[{}] SendShutdown()", this->client_id);
762
763 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SHUTDOWN);
764 this->SendPacket(std::move(p));
766}
767
770{
771 Debug(net, 9, "client[{}] SendNewGame()", this->client_id);
772
773 auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEWGAME);
774 this->SendPacket(std::move(p));
776}
777
784{
785 Debug(net, 9, "client[{}] SendRConResult()", this->client_id);
786
787 auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON);
788
789 p->Send_uint16(colour);
790 p->Send_string(command);
791 this->SendPacket(std::move(p));
793}
794
801{
802 Debug(net, 9, "client[{}] SendMove(): client_id={}", this->client_id, client_id);
803
804 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MOVE);
805
806 p->Send_uint32(client_id);
807 p->Send_uint8(company_id);
808 this->SendPacket(std::move(p));
810}
811
814{
815 Debug(net, 9, "client[{}] SendConfigUpdate()", this->client_id);
816
817 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CONFIG_UPDATE);
818
820 p->Send_string(_settings_client.network.server_name);
821 this->SendPacket(std::move(p));
823}
824
825/***********
826 * Receiving functions
827 ************/
828
830{
831 Debug(net, 9, "client[{}] Receive_CLIENT_GAME_INFO()", this->client_id);
832
833 return this->SendGameInfo();
834}
835
837{
838 if (this->status != STATUS_NEWGRFS_CHECK) {
839 /* Illegal call, return error and ignore the packet */
840 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
841 }
842
843 Debug(net, 9, "client[{}] Receive_CLIENT_NEWGRFS_CHECKED()", this->client_id);
844
845 return this->SendWelcome();
846}
847
849{
850 if (this->status != STATUS_INACTIVE) {
851 /* Illegal call, return error and ignore the packet */
852 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
853 }
854
856 /* Turns out we are full. Inform the user about this. */
857 return this->SendError(NETWORK_ERROR_FULL);
858 }
859
860 std::string client_revision = p.Recv_string(NETWORK_REVISION_LENGTH);
861 uint32_t newgrf_version = p.Recv_uint32();
862
863 Debug(net, 9, "client[{}] Receive_CLIENT_JOIN(): client_revision={}, newgrf_version={}", this->client_id, client_revision, newgrf_version);
864
865 /* Check if the client has revision control enabled */
866 if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
867 /* Different revisions!! */
868 return this->SendError(NETWORK_ERROR_WRONG_REVISION);
869 }
870
871 return this->SendAuthRequest();
872}
873
875{
876 if (this->status != STATUS_IDENTIFY) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
877
878 Debug(net, 9, "client[{}] Receive_CLIENT_IDENTIFY()", this->client_id);
879
880 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
881 CompanyID playas = (Owner)p.Recv_uint8();
882
884
885 /* join another company does not affect these values */
886 switch (playas.base()) {
887 case COMPANY_NEW_COMPANY.base(): // New company
889 return this->SendError(NETWORK_ERROR_FULL);
890 }
891 break;
892 case COMPANY_SPECTATOR.base(): // Spectator
893 break;
894 default: // Join another company (companies 1..MAX_COMPANIES (index 0..(MAX_COMPANIES-1)))
895 if (!Company::IsValidHumanID(playas)) {
896 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
897 }
898
899 if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) {
900 /* When we're not authorized, just bump us to a spectator. */
901 playas = COMPANY_SPECTATOR;
902 }
903 break;
904 }
905
906 if (!NetworkIsValidClientName(client_name)) {
907 /* An invalid client name was given. However, the client ensures the name
908 * is valid before it is sent over the network, so something went horribly
909 * wrong. This is probably someone trying to troll us. */
910 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
911 }
912
913 if (!NetworkMakeClientNameUnique(client_name)) { // Change name if duplicate
914 /* We could not create a name for this client */
915 return this->SendError(NETWORK_ERROR_NAME_IN_USE);
916 }
917
920 this->SetInfo(ci);
922 ci->client_name = std::move(client_name);
923 ci->client_playas = playas;
924 ci->public_key = this->peer_public_key;
925 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, ci->index);
926
927 /* Make sure companies to which people try to join are not autocleaned */
928 Company *c = Company::GetIfValid(playas);
929 if (c != nullptr) c->months_empty = 0;
930
931 return this->SendNewGRFCheck();
932}
933
934static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
935{
936 switch (method) {
938 return NETWORK_ERROR_WRONG_PASSWORD;
940 return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
941
942 default:
943 NOT_REACHED();
944 }
945}
946
948{
949 if (this->status != STATUS_AUTH_GAME) {
950 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
951 }
952
953 Debug(net, 9, "client[{}] Receive_CLIENT_AUTH_RESPONSE()", this->client_id);
954
955 auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
956 switch (this->authentication_handler->ReceiveResponse(p)) {
958 break;
959
961 return this->SendAuthRequest();
962
964 default:
965 return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
966 }
967
969 if (status != NETWORK_RECV_STATUS_OKAY) return status;
970
971 this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
972 this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
973 this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
974 this->authentication_handler = nullptr;
975
976 Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
977 this->status = STATUS_IDENTIFY;
978
979 /* Reset 'lag' counters */
981
983}
984
986{
987 /* The client was never joined.. so this is impossible, right?
988 * Ignore the packet, give the client a warning, and close the connection */
989 if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
990 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
991 }
992
993 Debug(net, 9, "client[{}] Receive_CLIENT_GETMAP()", this->client_id);
994
995 /* Check if someone else is receiving the map */
997 if (new_cs->status == STATUS_MAP) {
998 /* Tell the new client to wait */
999 Debug(net, 9, "client[{}] status = MAP_WAIT", this->client_id);
1000 this->status = STATUS_MAP_WAIT;
1001 return this->SendWait();
1002 }
1003 }
1004
1005 /* We receive a request to upload the map.. give it to the client! */
1006 return this->SendMap();
1007}
1008
1010{
1011 /* Client has the map, now start syncing */
1012 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
1013 Debug(net, 9, "client[{}] Receive_CLIENT_MAP_OK()", this->client_id);
1014
1015 std::string client_name = this->GetClientName();
1016
1017 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id);
1019
1020 Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name);
1021
1022 /* Mark the client as pre-active, and wait for an ACK
1023 * so we know it is done loading and in sync with us */
1024 Debug(net, 9, "client[{}] status = PRE_ACTIVE", this->client_id);
1025 this->status = STATUS_PRE_ACTIVE;
1027 this->SendFrame();
1028 this->SendSync();
1029
1030 /* This is the frame the client receives
1031 * we need it later on to make sure the client is not too slow */
1032 this->last_frame = _frame_counter;
1034
1036 if (new_cs->status >= STATUS_AUTHORIZED) {
1037 new_cs->SendClientInfo(this->GetInfo());
1038 new_cs->SendJoin(this->client_id);
1039 }
1040 }
1041
1042 NetworkAdminClientInfo(this, true);
1043
1044 /* also update the new client with our max values */
1045 return this->SendConfigUpdate();
1046 }
1047
1048 /* Wrong status for this packet, give a warning to client, and close connection */
1049 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1050}
1051
1057{
1058 /* The client was never joined.. so this is impossible, right?
1059 * Ignore the packet, give the client a warning, and close the connection */
1060 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1061 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1062 }
1063
1065 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
1066 }
1067
1068 Debug(net, 9, "client[{}] Receive_CLIENT_COMMAND()", this->client_id);
1069
1070 CommandPacket cp;
1071 auto err = this->ReceiveCommand(p, cp);
1072
1074
1075 NetworkClientInfo *ci = this->GetInfo();
1076
1077 if (err.has_value()) {
1078 IConsolePrint(CC_WARNING, "Dropping client #{} (IP: {}) due to {}.", ci->client_id, this->GetClientIP(), *err);
1079 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1080 }
1081
1083 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a server only command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1084 return this->SendError(NETWORK_ERROR_KICKED);
1085 }
1086
1088 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a non-spectator command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1089 return this->SendError(NETWORK_ERROR_KICKED);
1090 }
1091
1097 CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : CCA_NEW;
1098 if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
1099 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
1100 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1101 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
1102 }
1103
1104 if (cp.cmd == CMD_COMPANY_CTRL) {
1105 if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) {
1106 return this->SendError(NETWORK_ERROR_CHEATER);
1107 }
1108
1109 /* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */
1111 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
1113 }
1114 }
1115
1116 if (cp.cmd == CMD_COMPANY_ALLOW_LIST_CTRL) {
1117 /* Maybe the client just got moved before allowing? */
1119
1120 /* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
1121 std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_ALLOW_LIST_CTRL>::Args>(cp.data));
1122 bool found = false;
1124 if (info->public_key == public_key) {
1125 found = true;
1126 break;
1127 }
1128 }
1129
1130 /* Maybe the client just left? */
1131 if (!found) return NETWORK_RECV_STATUS_OKAY;
1132 }
1133
1135
1136 this->incoming_queue.push_back(std::move(cp));
1138}
1139
1141{
1142 /* This packets means a client noticed an error and is reporting this
1143 * to us. Display the error and report it to the other clients */
1145
1146 Debug(net, 9, "client[{}] Receive_CLIENT_ERROR(): errorno={}", this->client_id, errorno);
1147
1148 /* The client was never joined.. thank the client for the packet, but ignore it */
1149 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1151 }
1152
1153 std::string client_name = this->GetClientName();
1154 StringID strid = GetNetworkErrorMsg(errorno);
1155
1156 Debug(net, 1, "'{}' reported an error and is closing its connection: {}", client_name, GetString(strid));
1157
1158 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
1159
1161 if (new_cs->status >= STATUS_AUTHORIZED) {
1162 new_cs->SendErrorQuit(this->client_id, errorno);
1163 }
1164 }
1165
1166 NetworkAdminClientError(this->client_id, errorno);
1167
1169}
1170
1172{
1173 /* The client was never joined.. thank the client for the packet, but ignore it */
1174 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1176 }
1177
1178 Debug(net, 9, "client[{}] Receive_CLIENT_QUIT()", this->client_id);
1179
1180 /* The client wants to leave. Display this and report it to the other clients. */
1181 std::string client_name = this->GetClientName();
1182 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1183
1185 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
1186 new_cs->SendQuit(this->client_id);
1187 }
1188 }
1189
1191
1193}
1194
1196{
1197 if (this->status < STATUS_AUTHORIZED) {
1198 /* Illegal call, return error and ignore the packet */
1199 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1200 }
1201
1202 uint32_t frame = p.Recv_uint32();
1203
1204 Debug(net, 9, "client[{}] Receive_CLIENT_ACK(): frame={}", this->client_id, frame);
1205
1206 /* The client is trying to catch up with the server */
1207 if (this->status == STATUS_PRE_ACTIVE) {
1208 /* The client is not yet caught up? */
1210
1211 /* Now it is! Unpause the game */
1212 Debug(net, 9, "client[{}] status = ACTIVE", this->client_id);
1213 this->status = STATUS_ACTIVE;
1215
1216 /* Execute script for, e.g. MOTD */
1217 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
1218 }
1219
1220 /* Get, and validate the token. */
1221 uint8_t token = p.Recv_uint8();
1222 if (token == this->last_token) {
1223 /* We differentiate between last_token_frame and last_frame so the lag
1224 * test uses the actual lag of the client instead of the lag for getting
1225 * the token back and forth; after all, the token is only sent every
1226 * time we receive a PACKET_CLIENT_ACK, after which we will send a new
1227 * token to the client. If the lag would be one day, then we would not
1228 * be sending the new token soon enough for the new daily scheduled
1229 * PACKET_CLIENT_ACK. This would then register the lag of the client as
1230 * two days, even when it's only a single day. */
1232 /* Request a new token. */
1233 this->last_token = 0;
1234 }
1235
1236 /* The client received the frame, make note of it */
1237 this->last_frame = frame;
1238 /* With those 2 values we can calculate the lag realtime */
1241}
1242
1243
1254void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, std::string_view msg, ClientID from_id, int64_t data, bool from_admin)
1255{
1256 const NetworkClientInfo *ci, *ci_own, *ci_to;
1257
1258 switch (desttype) {
1259 case DESTTYPE_CLIENT:
1260 /* Are we sending to the server? */
1261 if ((ClientID)dest == CLIENT_ID_SERVER) {
1263 /* Display the text locally, and that is it */
1264 if (ci != nullptr) {
1265 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1266
1268 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1269 }
1270 }
1271 } else {
1272 /* Else find the client to send the message to */
1273 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1274 if (cs->client_id == (ClientID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1275 cs->SendChat(action, from_id, false, msg, data);
1276 break;
1277 }
1278 }
1279 }
1280
1281 /* Display the message locally (so you know you have sent it) */
1282 if (from_id != (ClientID)dest) {
1283 if (from_id == CLIENT_ID_SERVER) {
1286 if (ci != nullptr && ci_to != nullptr) {
1287 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
1288 }
1289 } else {
1290 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1291 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1292 cs->SendChat(action, (ClientID)dest, true, msg, data);
1293 break;
1294 }
1295 }
1296 }
1297 }
1298 break;
1299 case DESTTYPE_TEAM: {
1300 /* If this is false, the message is already displayed on the client who sent it. */
1301 bool show_local = true;
1302 /* Find all clients that belong to this company */
1303 ci_to = nullptr;
1304 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1305 ci = cs->GetInfo();
1306 if (ci != nullptr && ci->client_playas == (CompanyID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1307 cs->SendChat(action, from_id, false, msg, data);
1308 if (cs->client_id == from_id) show_local = false;
1309 ci_to = ci; // Remember a client that is in the company for company-name
1310 }
1311 }
1312
1313 /* if the server can read it, let the admin network read it, too. */
1315 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1316 }
1317
1320 if (ci != nullptr && ci_own != nullptr && ci_own->client_playas == dest) {
1321 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1322 if (from_id == CLIENT_ID_SERVER) show_local = false;
1323 ci_to = ci_own;
1324 }
1325
1326 /* There is no such client */
1327 if (ci_to == nullptr) break;
1328
1329 /* Display the message locally (so you know you have sent it) */
1330 if (ci != nullptr && show_local) {
1331 if (from_id == CLIENT_ID_SERVER) {
1332 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1333 std::string name = GetString(str, ci_to->client_playas);
1334 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
1335 } else {
1336 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1337 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1338 cs->SendChat(action, ci_to->client_id, true, msg, data);
1339 }
1340 }
1341 }
1342 }
1343 break;
1344 }
1345 default:
1346 Debug(net, 1, "Received unknown chat destination type {}; doing broadcast instead", desttype);
1347 [[fallthrough]];
1348
1349 case DESTTYPE_BROADCAST:
1350 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1351 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendChat(action, from_id, false, msg, data);
1352 }
1353
1354 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1355
1357 if (ci != nullptr) {
1358 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1359 }
1360 break;
1361 }
1362}
1363
1371void NetworkServerSendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
1372{
1373 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1374 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendExternalChat(source, colour, user, msg);
1375 }
1376 NetworkTextMessage(NETWORK_ACTION_EXTERNAL_CHAT, colour, false, user, msg, source);
1377}
1378
1380{
1381 if (this->status < STATUS_PRE_ACTIVE) {
1382 /* Illegal call, return error and ignore the packet */
1383 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1384 }
1385
1387 DestType desttype = (DestType)p.Recv_uint8();
1388 int dest = p.Recv_uint32();
1389
1390 Debug(net, 9, "client[{}] Receive_CLIENT_CHAT(): action={}, desttype={}, dest={}", this->client_id, action, desttype, dest);
1391
1392 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1393 int64_t data = p.Recv_uint64();
1394
1395 NetworkClientInfo *ci = this->GetInfo();
1396 switch (action) {
1397 case NETWORK_ACTION_CHAT:
1398 case NETWORK_ACTION_CHAT_CLIENT:
1399 case NETWORK_ACTION_CHAT_COMPANY:
1400 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
1401 break;
1402 default:
1403 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to unknown chact action.", ci->client_id, this->GetClientIP());
1404 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1405 }
1407}
1408
1410{
1411 if (this->status != STATUS_ACTIVE) {
1412 /* Illegal call, return error and ignore the packet */
1413 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1414 }
1415
1416 Debug(net, 9, "client[{}] Receive_CLIENT_SET_NAME()", this->client_id);
1417
1419
1420 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
1421 ci = this->GetInfo();
1422
1424
1425 if (ci != nullptr) {
1426 if (!NetworkIsValidClientName(client_name)) {
1427 /* An invalid client name was given. However, the client ensures the name
1428 * is valid before it is sent over the network, so something went horribly
1429 * wrong. This is probably someone trying to troll us. */
1430 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
1431 }
1432
1433 /* Display change */
1434 if (NetworkMakeClientNameUnique(client_name)) {
1435 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
1436 ci->client_name = std::move(client_name);
1438 }
1439 }
1441}
1442
1444{
1445 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1446
1447 Debug(net, 9, "client[{}] Receive_CLIENT_RCON()", this->client_id);
1448
1449 std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
1450 std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1451
1452 if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
1453 /* We are allowed, nothing more to validate. */
1454 } else if (_settings_client.network.rcon_password.empty()) {
1456 } else if (_settings_client.network.rcon_password != password) {
1457 Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id);
1459 }
1460
1461 Debug(net, 3, "[rcon] Client-id {} executed: {}", this->client_id, command);
1462
1464 IConsoleCmdExec(command);
1467}
1468
1470{
1471 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1472
1473 CompanyID company_id = (Owner)p.Recv_uint8();
1474
1475 Debug(net, 9, "client[{}] Receive_CLIENT_MOVE(): company_id={}", this->client_id, company_id);
1476
1477 /* Check if the company is valid, we don't allow moving to AI companies */
1478 if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
1479
1480 if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) {
1481 Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
1483 }
1484
1485 /* if we get here we can move the client */
1486 NetworkServerDoMove(this->client_id, company_id);
1488}
1489
1494{
1495 NetworkCompanyStatsArray stats = {};
1496
1497 /* Go through all vehicles and count the type of vehicles */
1498 for (const Vehicle *v : Vehicle::Iterate()) {
1499 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1500 uint8_t type = 0;
1501 switch (v->type) {
1502 case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
1503 case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
1504 case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
1505 case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
1506 default: continue;
1507 }
1508 stats[v->owner].num_vehicle[type]++;
1509 }
1510
1511 /* Go through all stations and count the types of stations */
1512 for (const Station *s : Station::Iterate()) {
1513 if (Company::IsValidID(s->owner)) {
1514 NetworkCompanyStats *npi = &stats[s->owner];
1515
1516 if (s->facilities.Test(StationFacility::Train)) npi->num_station[NETWORK_VEH_TRAIN]++;
1517 if (s->facilities.Test(StationFacility::TruckStop)) npi->num_station[NETWORK_VEH_LORRY]++;
1518 if (s->facilities.Test(StationFacility::BusStop)) npi->num_station[NETWORK_VEH_BUS]++;
1519 if (s->facilities.Test(StationFacility::Airport)) npi->num_station[NETWORK_VEH_PLANE]++;
1520 if (s->facilities.Test(StationFacility::Dock)) npi->num_station[NETWORK_VEH_SHIP]++;
1521 }
1522 }
1523
1524 return stats;
1525}
1526
1532{
1534
1535 if (ci == nullptr) return;
1536
1537 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, client_id);
1538
1539 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1541 cs->SendClientInfo(ci);
1542 }
1543 }
1544
1546}
1547
1554{
1555 CompanyMask has_clients{};
1556 CompanyMask has_vehicles{};
1557
1559
1560 /* Detect the active companies */
1561 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1562 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1563 }
1564
1565 if (!_network_dedicated) {
1567 assert(ci != nullptr);
1568 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1569 }
1570
1572 for (const Company *c : Company::Iterate()) {
1573 if (std::any_of(std::begin(c->group_all), std::end(c->group_all), [](const GroupStatistics &gs) { return gs.num_vehicle != 0; })) has_vehicles.Set(c->index);
1574 }
1575 }
1576
1577 /* Go through all the companies */
1578 for (Company *c : Company::Iterate()) {
1579 /* Skip the non-active once */
1580 if (c->is_ai) continue;
1581
1582 if (!has_clients.Test(c->index)) {
1583 /* The company is empty for one month more */
1584 if (c->months_empty != std::numeric_limits<decltype(c->months_empty)>::max()) c->months_empty++;
1585
1586 /* Is the company empty for autoclean_protected-months? */
1588 /* Shut the company down */
1590 IConsolePrint(CC_INFO, "Auto-cleaned company #{}.", c->index + 1);
1591 }
1592 /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
1593 if (_settings_client.network.autoclean_novehicles != 0 && c->months_empty > _settings_client.network.autoclean_novehicles && !has_vehicles.Test(c->index)) {
1594 /* Shut the company down */
1596 IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
1597 }
1598 } else {
1599 /* It is not empty, reset the date */
1600 c->months_empty = 0;
1601 }
1602 }
1603}
1604
1610bool NetworkMakeClientNameUnique(std::string &name)
1611{
1612 bool is_name_unique = false;
1613 std::string original_name = name;
1614
1615 for (uint number = 1; !is_name_unique && number <= MAX_CLIENTS; number++) { // Something's really wrong when there're more names than clients
1616 is_name_unique = true;
1617 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1618 if (ci->client_name == name) {
1619 /* Name already in use */
1620 is_name_unique = false;
1621 break;
1622 }
1623 }
1624 /* Check if it is the same as the server-name */
1626 if (ci != nullptr) {
1627 if (ci->client_name == name) is_name_unique = false; // name already in use
1628 }
1629
1630 if (!is_name_unique) {
1631 /* Try a new name (<name> #1, <name> #2, and so on) */
1632 name = fmt::format("{} #{}", original_name, number);
1633
1634 /* The constructed client name is larger than the limit,
1635 * so... bail out as no valid name can be created. */
1636 if (name.size() >= NETWORK_CLIENT_NAME_LENGTH) return false;
1637 }
1638 }
1639
1640 return is_name_unique;
1641}
1642
1649bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
1650{
1651 /* Check if the name's already in use */
1653 if (ci->client_name == new_name) return false;
1654 }
1655
1657 if (ci == nullptr) return false;
1658
1659 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
1660
1661 ci->client_name = new_name;
1662
1663 NetworkUpdateClientInfo(client_id);
1664 return true;
1665}
1666
1671static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
1672{
1673 for (auto &cp : cs->outgoing_queue) cs->SendCommand(cp);
1674 cs->outgoing_queue.clear();
1675}
1676
1681void NetworkServer_Tick(bool send_frame)
1682{
1683#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1684 bool send_sync = false;
1685#endif
1686
1687#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1690 send_sync = true;
1691 }
1692#endif
1693
1694 /* Now we are done with the frame, inform the clients that they can
1695 * do their frame! */
1696 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1697 /* We allow a number of bytes per frame, but only to the burst amount
1698 * to be available for packet receiving at any particular time. */
1699 cs->receive_limit = std::min<size_t>(cs->receive_limit + _settings_client.network.bytes_per_frame,
1701
1702 /* Check if the speed of the client is what we can expect from a client */
1703 uint lag = NetworkCalculateLag(cs);
1704 switch (cs->status) {
1705 case NetworkClientSocket::STATUS_ACTIVE:
1707 /* Client did still not report in within the specified limit. */
1708
1709 if (cs->last_packet + std::chrono::milliseconds(lag * MILLISECONDS_PER_TICK) > std::chrono::steady_clock::now()) {
1710 /* A packet was received in the last three game days, so the client is likely lagging behind. */
1711 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client's game state is more than {} ticks behind.", cs->client_id, cs->GetClientIP(), lag);
1712 } else {
1713 /* No packet was received in the last three game days; sounds like a lost connection. */
1714 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client did not respond for more than {} ticks.", cs->client_id, cs->GetClientIP(), lag);
1715 }
1716 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1717 continue;
1718 }
1719
1720 /* Report once per time we detect the lag, and only when we
1721 * received a packet in the last 2 seconds. If we
1722 * did not receive a packet, then the client is not just
1723 * slow, but the connection is likely severed. Mentioning
1724 * frame_freq is not useful in this case. */
1725 if (lag > (uint)Ticks::DAY_TICKS && cs->lag_test == 0 && cs->last_packet + std::chrono::seconds(2) > std::chrono::steady_clock::now()) {
1726 IConsolePrint(CC_WARNING, "[{}] Client #{} is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
1727 cs->lag_test = 1;
1728 }
1729
1730 if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) {
1731 /* This is a bad client! It didn't send the right token back within time. */
1732 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it fails to send valid acks.", cs->client_id, cs->GetClientIP());
1733 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1734 continue;
1735 }
1736 break;
1737
1738 case NetworkClientSocket::STATUS_INACTIVE:
1739 case NetworkClientSocket::STATUS_IDENTIFY:
1740 case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
1741 case NetworkClientSocket::STATUS_AUTHORIZED:
1742 /* NewGRF check and authorized states should be handled almost instantly.
1743 * So give them some lee-way, likewise for the query with inactive. */
1745 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to start the joining process.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_init_time);
1746 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1747 continue;
1748 }
1749 break;
1750
1751 case NetworkClientSocket::STATUS_MAP_WAIT:
1752 /* Send every two seconds a packet to the client, to make sure
1753 * it knows the server is still there; just someone else is
1754 * still receiving the map. */
1755 if (std::chrono::steady_clock::now() > cs->last_packet + std::chrono::seconds(2)) {
1756 cs->SendWait();
1757 /* We need to reset the timer, as otherwise we will be
1758 * spamming the client. Strictly speaking this variable
1759 * tracks when we last received a packet from the client,
1760 * but as it is waiting, it will not send us any till we
1761 * start sending them data. */
1762 cs->last_packet = std::chrono::steady_clock::now();
1763 }
1764 break;
1765
1766 case NetworkClientSocket::STATUS_MAP:
1767 /* Downloading the map... this is the amount of time since starting the saving. */
1769 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to download the map.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_download_time);
1770 cs->SendError(NETWORK_ERROR_TIMEOUT_MAP);
1771 continue;
1772 }
1773 break;
1774
1775 case NetworkClientSocket::STATUS_DONE_MAP:
1776 case NetworkClientSocket::STATUS_PRE_ACTIVE:
1777 /* The map has been sent, so this is for loading the map and syncing up. */
1779 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to join.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_join_time);
1780 cs->SendError(NETWORK_ERROR_TIMEOUT_JOIN);
1781 continue;
1782 }
1783 break;
1784
1785 case NetworkClientSocket::STATUS_AUTH_GAME:
1786 /* These don't block? */
1788 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to enter the password.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_password_time);
1789 cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD);
1790 continue;
1791 }
1792 break;
1793
1794 case NetworkClientSocket::STATUS_END:
1795 /* Bad server/code. */
1796 NOT_REACHED();
1797 }
1798
1799 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
1800 /* Check if we can send command, and if we have anything in the queue */
1802
1803 /* Send an updated _frame_counter_max to the client */
1804 if (send_frame) cs->SendFrame();
1805
1806#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1807 /* Send a sync-check packet */
1808 if (send_sync) cs->SendSync();
1809#endif
1810 }
1811 }
1812}
1813
1816{
1819 case FT_SAVEGAME:
1820 case FT_SCENARIO:
1822 break;
1823
1824 case FT_HEIGHTMAP:
1826 break;
1827
1828 default:
1830 }
1831}
1832
1835{
1836 if (!_network_server) return;
1837
1838 /* If setting is 0, this feature is disabled. */
1839 if (_settings_client.network.restart_hours == 0) return;
1840
1841 Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);
1843});
1844
1850{
1851 if (!_network_server) return;
1852
1854}
1855
1858{
1859 /* If setting is 0, this feature is disabled. */
1861
1863 Debug(net, 3, "Auto-restarting map: year {} reached", TimerGameCalendar::year);
1865 }
1866}
1867
1869static const IntervalTimer<TimerGameCalendar> _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) {
1870 if (!_network_server) return;
1871
1873});
1874
1876static const IntervalTimer<TimerGameEconomy> _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto)
1877{
1878 if (!_network_server) return;
1879
1881});
1882
1884static const IntervalTimer<TimerGameEconomy> _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto)
1885{
1886 if (!_network_server) return;
1887
1890});
1891
1893static const IntervalTimer<TimerGameEconomy> _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto)
1894{
1895 if (!_network_server) return;
1896
1899});
1900
1902static const IntervalTimer<TimerGameEconomy> _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto)
1903{
1904 if (!_network_server) return;
1905
1907});
1908
1910static const IntervalTimer<TimerGameEconomy> _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto)
1911{
1912 if (!_network_server) return;
1913
1915});
1916
1922{
1923 return this->client_address.GetHostname();
1924}
1925
1928{
1929 static const std::string_view stat_str[] = {
1930 "inactive",
1931 "authorizing",
1932 "identifying client",
1933 "checking NewGRFs",
1934 "authorized",
1935 "waiting",
1936 "loading map",
1937 "map done",
1938 "ready",
1939 "active"
1940 };
1941 static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
1942
1943 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1944 NetworkClientInfo *ci = cs->GetInfo();
1945 if (ci == nullptr) continue;
1946 uint lag = NetworkCalculateLag(cs);
1947
1948 std::string_view status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
1949 IConsolePrint(CC_INFO, "Client #{} name: '{}' status: '{}' frame-lag: {} company: {} IP: {}",
1950 cs->client_id, ci->client_name, status, lag,
1951 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
1952 cs->GetClientIP());
1953 }
1954}
1955
1960{
1961 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1962 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
1963 }
1964}
1965
1971
1978void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
1979{
1980 /* Only allow non-dedicated servers and normal clients to be moved */
1981 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
1982
1984 assert(ci != nullptr);
1985
1986 /* No need to waste network resources if the client is in the company already! */
1987 if (ci->client_playas == company_id) return;
1988
1989 ci->client_playas = company_id;
1990
1991 if (client_id == CLIENT_ID_SERVER) {
1992 SetLocalCompany(company_id);
1993 } else {
1994 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
1995 /* When the company isn't authorized we can't move them yet. */
1996 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
1997 cs->SendMove(client_id, company_id);
1998 }
1999
2000 /* Announce the client's move. */
2001 NetworkUpdateClientInfo(client_id);
2002
2003 if (company_id == COMPANY_SPECTATOR) {
2004 /* The client has joined spectators. */
2005 NetworkServerSendChat(NETWORK_ACTION_COMPANY_SPECTATOR, DESTTYPE_BROADCAST, 0, "", client_id);
2006 } else {
2007 /* The client has joined another company. */
2008 std::string company_name = GetString(STR_COMPANY_NAME, company_id);
2009 NetworkServerSendChat(NETWORK_ACTION_COMPANY_JOIN, DESTTYPE_BROADCAST, 0, company_name, client_id);
2010 }
2011
2013}
2014
2021void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, std::string_view string)
2022{
2023 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
2024}
2025
2031void NetworkServerKickClient(ClientID client_id, std::string_view reason)
2032{
2033 if (client_id == CLIENT_ID_SERVER) return;
2034 NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED, reason);
2035}
2036
2043uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
2044{
2045 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban, reason);
2046}
2047
2054uint NetworkServerKickOrBanIP(std::string_view ip, bool ban, std::string_view reason)
2055{
2056 /* Add address to ban-list */
2057 if (ban) {
2058 bool contains = false;
2059 for (const auto &iter : _network_ban_list) {
2060 if (iter == ip) {
2061 contains = true;
2062 break;
2063 }
2064 }
2065 if (!contains) _network_ban_list.emplace_back(ip);
2066 }
2067
2068 uint n = 0;
2069
2070 /* There can be multiple clients with the same IP, kick them all but don't kill the server,
2071 * or the client doing the rcon. The latter can't be kicked because kicking frees closes
2072 * and subsequently free the connection related instances, which we would be reading from
2073 * and writing to after returning. So we would read or write data from freed memory up till
2074 * the segfault triggers. */
2075 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2076 if (cs->client_id == CLIENT_ID_SERVER) continue;
2077 if (cs->client_id == _redirect_console_to_client) continue;
2078 if (cs->client_address.IsInNetmask(ip)) {
2079 NetworkServerKickClient(cs->client_id, reason);
2080 n++;
2081 }
2082 }
2083
2084 return n;
2085}
2086
2093{
2094 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
2095 if (ci->client_playas == company) return true;
2096 }
2097 return false;
2098}
2099
2100
2107{
2108 const NetworkClientInfo *ci = this->GetInfo();
2109 if (ci != nullptr && !ci->client_name.empty()) return ci->client_name;
2110
2111 return fmt::format("Client #{}", this->client_id);
2112}
2113
2118{
2120 if (_network_server) {
2121 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {} IP: {}",
2122 ci->client_id,
2123 ci->client_name,
2124 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2125 ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP());
2126 } else {
2127 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {}",
2128 ci->client_id,
2129 ci->client_name,
2130 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0));
2131 }
2132 }
2133}
2134
2140std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
2141{
2142 auto socket = NetworkClientSocket::GetByClientID(client_id);
2143 return socket == nullptr ? "" : socket->GetPeerPublicKey();
2144}
2145
2146
2153{
2154 assert(c != nullptr);
2155
2156 if (!_network_server) return;
2157
2158 if (ci != nullptr) {
2159 /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
2160 ci->client_playas = c->index;
2162
2163 /*
2164 * This function is called from a command, but is only called for the server.
2165 * The client information is managed out-of-band from the commands, so to not have a
2166 * different state/president/company name in the different clients, we need to
2167 * circumvent the normal ::Post logic and go directly to sending the command.
2168 */
2171
2172 NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
2173 }
2174}
std::map< SOCKET, NetworkAddress > SocketList
Type for a mapping between address and socket.
Definition address.h:21
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
void SetInterval(const TPeriod interval, bool reset=true)
Set a new interval for the timer.
Definition timer.h:99
const std::string & GetHostname()
Get the hostname; in case it wasn't given the IPv4 dotted representation is given.
Definition address.cpp:24
Default implementation for the authorized key handler.
bool IsAllowed(std::string_view peer_public_key) const override
Check whether the given public key of the peer is allowed in.
Default implementation of the password provider.
static std::unique_ptr< NetworkAuthenticationServerHandler > Create(const NetworkAuthenticationPasswordProvider *password_provider, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler, NetworkAuthenticationMethodMask client_supported_method_mask={NetworkAuthenticationMethod::X25519_KeyExchangeOnly, NetworkAuthenticationMethod::X25519_PAKE, NetworkAuthenticationMethod::X25519_AuthorizedKey})
Create a NetworkAuthenticationServerHandler.
@ RetryNextMethod
The client failed to authenticate, but there is another method to try.
@ NotAuthenticated
All authentications for this handler have been exhausted.
@ Authenticated
The client was authenticated successfully.
Base socket handler for all TCP sockets.
Definition tcp_game.h:138
uint32_t last_frame
Last frame we have executed.
Definition tcp_game.h:484
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition tcp_game.h:512
std::optional< std::string_view > ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
ClientID client_id
Client identifier.
Definition tcp_game.h:483
CommandQueue incoming_queue
The command-queue awaiting handling.
Definition tcp_game.h:486
std::chrono::steady_clock::time_point last_packet
Time we received the last frame.
Definition tcp_game.h:487
void SetInfo(NetworkClientInfo *info)
Sets the client info for this socket handler.
Definition tcp_game.h:502
uint32_t last_frame_server
Last frame the server has executed.
Definition tcp_game.h:485
NetworkClientInfo * info
Client info related to this socket.
Definition tcp_game.h:141
void SendCommand(Packet &p, const CommandPacket &cp)
Sends a command over the network.
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition core.h:72
std::unique_ptr< class NetworkEncryptionHandler > send_encryption_handler
The handler for encrypting sent packets.
Definition core.h:48
std::unique_ptr< class NetworkEncryptionHandler > receive_encryption_handler
The handler for decrypting received packets.
Definition core.h:47
virtual std::unique_ptr< Packet > ReceivePacket()
Receives a packet for the given client.
Definition tcp.cpp:117
SOCKET sock
The socket currently connected to.
Definition tcp.h:36
virtual void SendPacket(std::unique_ptr< Packet > &&packet)
This function puts the packet in the send-queue and it is send as soon as possible.
Definition tcp.cpp:56
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition tcp.cpp:74
Class for handling the server side of the game connection.
NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet &p) override
Gives the client a new name: string New name of the client.
static std::string_view GetName()
Get the name used by the listener.
size_t receive_limit
Amount of bytes that we can receive at this moment.
std::shared_ptr< struct PacketWriter > savegame
Writer used to write the savegame.
static void Send()
Send the packets for the server sockets.
NetworkRecvStatus Receive_CLIENT_MOVE(Packet &p) override
Request the server to move this client into another company: uint8_t ID of the company the client wan...
NetworkRecvStatus SendQuit(ClientID client_id)
Tell the client another client quit.
NetworkRecvStatus Receive_CLIENT_ACK(Packet &p) override
Tell the server we are done with this frame: uint32_t Current frame counter of the client.
NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p) override
Send the response to the authentication request: 32 * uint8_t Public key of the client.
std::unique_ptr< Packet > ReceivePacket() override
Receives a packet for the given client.
@ STATUS_PRE_ACTIVE
The client is catching up the delayed frames.
@ STATUS_IDENTIFY
The client is identifying itself.
@ STATUS_AUTH_GAME
The client is authorizing with game (server) password.
@ STATUS_NEWGRFS_CHECK
The client is checking NewGRFs.
@ STATUS_AUTHORIZED
The client is authorized.
@ STATUS_INACTIVE
The client is not connected nor active.
@ STATUS_MAP
The client is downloading the map.
@ STATUS_DONE_MAP
The client has downloaded the map.
@ STATUS_ACTIVE
The client is active within in the game.
@ STATUS_MAP_WAIT
The client is waiting as someone else is downloading the map.
NetworkRecvStatus Receive_CLIENT_COMMAND(Packet &p) override
The client has done a command and wants us to handle it.
NetworkRecvStatus SendRConResult(uint16_t colour, std::string_view command)
Send the result of a console action.
NetworkRecvStatus Receive_CLIENT_QUIT(Packet &p) override
The client is quitting the game.
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, std::string_view msg, int64_t data)
Send a chat message.
NetworkRecvStatus SendWelcome()
Send the client a welcome message with some basic information.
NetworkRecvStatus SendAuthRequest()
Request the game password.
std::string GetClientName() const
Get the name of the client, if the user did not send it yet, Client ID is used.
uint8_t last_token
The last random token we did send to verify the client is listening.
NetworkRecvStatus SendFrame()
Tell the client that they may run to a particular frame.
NetworkRecvStatus Receive_CLIENT_ERROR(Packet &p) override
The client made an error and is quitting the game.
NetworkRecvStatus SendGameInfo()
Send the client information about the server.
NetworkRecvStatus SendJoin(ClientID client_id)
Tell that a client joined.
~ServerNetworkGameSocketHandler() override
Clear everything related to this client.
std::string peer_public_key
The public key of our client.
NetworkRecvStatus Receive_CLIENT_CHAT(Packet &p) override
Sends a chat-packet to the server: uint8_t ID of the action (see NetworkAction).
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci)
Send the client information about a client.
static bool AllowConnection()
Whether an connection is allowed or not at this moment.
NetworkRecvStatus SendEnableEncryption()
Notify the client that the authentication has completed and tell that for the remainder of this socke...
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override
Try to join the server: string OpenTTD revision (norev0000 if no revision).
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override
Request game information.
NetworkRecvStatus SendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
Send a chat message from external source.
ServerNetworkGameSocketHandler(ClientPoolID index, SOCKET s)
Create a new socket for the server side of the game connection.
NetworkRecvStatus SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
Tell the client another client quit with an error.
NetworkAddress client_address
IP-address of the client (so they can be banned)
NetworkRecvStatus SendNewGame()
Tell the client we're starting a new game.
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override
Request the map from the server.
NetworkRecvStatus SendSync()
Request the client to sync.
std::unique_ptr< class NetworkAuthenticationServerHandler > authentication_handler
The handler for the authentication.
NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id)
Tell that a client moved to another company.
NetworkRecvStatus Receive_CLIENT_RCON(Packet &p) override
Send an RCon command to the server: string RCon password.
NetworkRecvStatus SendError(NetworkErrorCode error, std::string_view reason={})
Send an error to the client, and close its connection.
NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p) override
The client tells the server about the identity of the client: string Name of the client (max NETWORK_...
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override
Close the network connection due to the given status.
NetworkRecvStatus SendMap()
This sends the map to the client.
NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet &p) override
Tell the server that we have the required GRFs.
uint32_t last_token_frame
The last frame we received the right token.
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet &p) override
Tell the server that we are done receiving/loading the map.
NetworkRecvStatus SendShutdown()
Tell the client we're shutting down.
ClientStatus status
Status of this client.
NetworkRecvStatus SendNewGRFCheck()
Send the check for the NewGRFs.
std::string_view GetClientIP()
Get the IP address/hostname of the connected client.
NetworkRecvStatus SendConfigUpdate()
Send an update about the max company/spectator counts.
NetworkRecvStatus SendWait()
Tell the client that its put in a waiting queue.
NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the client to execute.
Template for TCP listeners.
Definition tcp_listen.h:28
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Year year
Current year, starting at 0.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
@ UNPAUSED
Only run when not paused.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific type.
CommandFlags GetCommandFlags(Commands cmd)
This function mask the parameter with CMD_ID_MASK and returns the flags which belongs to the given co...
Definition command.cpp:118
@ Spectator
the command may be initiated by a spectator
@ Server
the command can only be initiated by the server
@ ClientID
set p2 with the ClientID of the sending client.
@ CMD_COMPANY_CTRL
used in multiplayer to create a new companies etc.
@ CMD_COMPANY_ALLOW_LIST_CTRL
Used in multiplayer to add/remove a client's public key to/from the company's allow list.
TextColour GetDrawStringCompanyColour(CompanyID company)
Get the colour for DrawString-subroutines which matches the colour of the company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
void SetLocalCompany(CompanyID new_company)
Sets the local company and updates the settings that are set on a per-company basis to reflect the co...
CompanyCtrlAction
The action to do with CMD_COMPANY_CTRL.
@ CCA_DELETE
Delete a company.
@ CCA_NEW
Create a new company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
@ CALCA_ADD
Create a public key.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ CRR_AUTOCLEAN
The company is removed due to autoclean.
static const size_t TCP_MTU
Number of bytes we can pack in a single TCP packet.
Definition config.h:43
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:56
static const uint NETWORK_CHAT_LENGTH
The maximum length of a chat message, in bytes including '\0'.
Definition config.h:59
static const uint NETWORK_REVISION_LENGTH
The maximum length of the revision, in bytes including '\0'.
Definition config.h:54
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition config.h:57
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:55
void IConsoleCmdExec(std::string_view command_string, const uint recurse_count)
Execute a given command passed to us.
Definition console.cpp:269
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition console.cpp:90
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_WARNING
Colour for warning lines.
static const TextColour CC_DEFAULT
Default colour of the console.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition core.h:21
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition core.h:26
@ NETWORK_RECV_STATUS_SERVER_ERROR
The server told us we made an error.
Definition core.h:28
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition core.h:22
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition core.h:27
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
#define DECLARE_INCREMENT_DECREMENT_OPERATORS(enum_type)
For some enums it is useful to have pre/post increment/decrement operators.
Definition enum_type.hpp:63
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:20
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:21
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:19
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:25
SwitchMode _switch_mode
The next mainloop command.
Definition gfx.cpp:49
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition gfx_type.h:370
uint32_t _last_sync_frame
Used in the server to store the last time a sync packet was sent to clients.
Definition network.cpp:80
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve the string id of an internal error number.
Definition network.cpp:310
ClientID _redirect_console_to_client
If not invalid, redirect the console output to a client.
Definition network.cpp:72
uint32_t _frame_counter
The current frame.
Definition network.cpp:79
StringList _network_ban_list
The banned clients.
Definition network.cpp:76
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:69
bool _network_server
network-server is active
Definition network.cpp:67
uint32_t _sync_seed_1
Seed to compare during sync checks.
Definition network.cpp:82
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:90
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:78
void NetworkAdminClientUpdate(const NetworkClientInfo *ci)
Notify the admin network of a client update (if they did opt in for the respective update).
void NetworkAdminClientQuit(ClientID client_id)
Notify the admin network that a client quit (if they have opt in for the respective update).
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, std::string_view msg, int64_t data, bool from_admin)
Send chat to the admin network (if they did opt in for the respective update).
void NetworkAdminUpdate(AdminUpdateFrequency freq)
Send (push) updates to the admin network as they have registered for these updates.
void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client)
Notify the admin network of a new client (if they did opt in for the respective update).
void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code)
Notify the admin network of a client error (if they have opt in for the respective update).
Server part of the admin network protocol.
Base core network types and some helper functions to access them.
bool NetworkIsValidClientName(std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
void NetworkSyncCommandQueue(NetworkClientSocket *cs)
Sync our local command queue to the command queue of the given socket.
void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
Insert a client ID into the command data in a command packet.
NetworkAuthenticationMethod
The authentication method that can be used.
@ X25519_PAKE
Authentication using x25519 password-authenticated key agreement.
@ X25519_AuthorizedKey
Authentication using x22519 key exchange and authorized keys.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, std::string_view msg, ClientID from_id, int64_t data=0, bool from_admin=false)
Send an actual chat message.
void SerializeNetworkGameInfo(Packet &p, const NetworkServerGameInfo &info, bool send_newgrf_names)
Serializes the NetworkGameInfo struct to the packet.
const NetworkServerGameInfo & GetCurrentNetworkServerGameInfo()
Get the NetworkServerGameInfo structure with the latest information of the server.
void SerializeGRFIdentifier(Packet &p, const GRFIdentifier &grf)
Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet.
void FillStaticNetworkServerGameInfo()
Fill a NetworkServerGameInfo structure with the static content, or things that are so static they can...
NetworkServerGameInfo _network_game_info
Information about our game.
bool IsNetworkCompatibleVersion(std::string_view other)
Checks whether the given version string is compatible with our version.
Convert NetworkGameInfo to Packet and back.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
Change the client name of the given client.
void NetworkServerSendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
Send a chat message from external source.
void NetworkPrintClients()
Print all the clients to the console.
void NetworkServerUpdateGameInfo()
Update the server's NetworkServerGameInfo due to changes in settings.
NetworkCompanyStatsArray NetworkGetCompanyStats()
Get the company stats.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, std::string_view msg, ClientID from_id, int64_t data, bool from_admin)
Send an actual chat message.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler(_settings_client.network.rcon_authorized_keys)
Provides the authorized key validation for rcon.
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password)
Provides the password validation for the game's password.
void NetworkServerSendConfigUpdate()
Send Config Update.
static const IntervalTimer< TimerGameEconomy > _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::Weekly);})
Economy weekly "callback".
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
void ChangeNetworkRestartTime(bool reset)
Reset the automatic network restart time interval.
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
static void NetworkRestartMap()
Helper function to restart the map.
void NetworkServerKickClient(ClientID client_id, std::string_view reason)
Kick a single client.
static void NetworkCheckRestartMapYear()
Check if we want to restart the map based on the year.
bool NetworkMakeClientNameUnique(std::string &name)
Check whether a name is unique, and otherwise try to make it unique.
static ClientID _network_client_id
The identifier counter for new clients (is never decreased)
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
Get the public key of the client with the given id.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler(_settings_client.network.server_authorized_keys)
Provides the authorized key handling for the game authentication.
static const IntervalTimer< TimerGameEconomy > _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::Daily);})
Daily "callback".
static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
Handle the command-queue of a socket.
static const IntervalTimer< TimerGameCalendar > _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) { if(!_network_server) return;NetworkCheckRestartMapYear();})
Calendar yearly "callback".
static const IntervalTimer< TimerGameEconomy > _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(AdminUpdateFrequency::Quarterly);})
Quarterly "callback".
void NetworkServerShowStatusToConsole()
Show the status message of all clients on the console.
void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
Perform all the server specific administration of a new company.
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, std::string_view string)
Send an rcon reply to the client.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
Ban, or kick, everyone joined from the given client's IP.
void NetworkServer_Tick(bool send_frame)
This is called every tick if this is a _network_server.
NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket")
Make very sure the preconditions given in network_type.h are actually followed.
static IntervalTimer< TimerGameRealtime > _network_restart_map_timer({std::chrono::hours::zero(), TimerGameRealtime::UNPAUSED}, [](auto) { if(!_network_server) return;if(_settings_client.network.restart_hours==0) return;Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);NetworkRestartMap();})
Timer to restart a network server automatically based on real-time hours played.
static const IntervalTimer< TimerGameEconomy > _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(AdminUpdateFrequency::Monthly);})
Economy monthly "callback".
static void NetworkAutoCleanCompanies()
Remove companies that have not been used depending on the autoclean_companies setting and values for ...
static const IntervalTimer< TimerGameEconomy > _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::Annually);})
Economy yearly "callback".
Server part of the network protocol.
DestType
Destination of our chat messages.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
@ DESTTYPE_BROADCAST
Send message/notice to all clients (All)
NetworkErrorCode
The error codes we send around in the protocols.
NetworkAction
Actions that can be used for NetworkTextMessage.
static const uint MAX_CLIENTS
How many clients can we have.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
@ CLIENT_ID_FIRST
The first client ID.
Sending and receiving UDP messages.
GRFConfigList _grfconfig
First item in list of current GRF set up.
@ Static
GRF file is used statically (can be used in any MP game)
@ SM_START_HEIGHTMAP
Load a heightmap and start a new game from it.
Definition openttd.h:38
@ SM_LOAD_GAME
Load game, Play Scenario.
Definition openttd.h:32
@ SM_NEWGAME
New Game --> 'Random game'.
Definition openttd.h:28
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
void SlError(StringID string, const std::string &extra_msg)
Error handler.
Definition saveload.cpp:339
SaveOrLoadResult SaveWithFilter(std::shared_ptr< SaveFilter > writer, bool threaded)
Save the game using a (writer) filter.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:78
@ SL_OK
completed successfully
Definition saveload.h:423
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:62
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
@ Dock
Station with a dock.
@ TruckStop
Station with truck stops.
@ Train
Station with train station.
@ Airport
Station with an airport.
@ BusStop
Station with bus stops.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
NetworkSettings network
settings related to the network
Everything we need to know about a command to be able to execute it.
CommandDataBuffer data
command parameters.
uint32_t frame
the frame in which this packet is executed
CompanyID company
company that is executing the command
bool my_cmd
did the command originate from "me"
Commands cmd
command being executed.
Defines the traits of a command.
uint8_t months_empty
NOSAVE: Number of months this company has not had a client in multiplayer.
static bool IsValidHumanID(auto index)
Is this company a valid company, not controlled by a NoAI program?
FiosType ftype
File type.
Definition saveload.h:431
AbstractFileType abstract
Abstract file type.
Definition fileio_type.h:64
uint32_t generation_seed
noise seed for world generation
GameCreationSettings game_creation
settings used during the creation of a game (map)
Statistics and caches on the vehicles in a group.
Definition group.h:25
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:117
TimerGameEconomy::Date join_date
Gamedate the client has joined.
CompanyID client_playas
As which company is this client playing (CompanyID)
ClientID client_id
Client identifier (same as ClientState->client_id)
std::string client_name
Name of the client.
std::string public_key
The public key of the client.
Simple calculated statistics of a company.
uint16_t num_station[NETWORK_VEH_END]
How many stations are there of this type?
uint8_t clients_on
Current count of clients on server.
uint8_t max_clients
maximum amount of clients
uint16_t bytes_per_frame_burst
how many bytes may, over a short period, be received?
bool autoclean_companies
automatically remove companies that are not in use
bool server_admin_chat
allow private chat for the server to be distributed to the admin network
TimerGameCalendar::Year restart_game_year
year the server restarts
uint8_t max_companies
maximum amount of companies
uint8_t autoclean_protected
Remove companies after this many months.
uint16_t max_password_time
maximum amount of time, in game ticks, a client may take to enter the password
uint16_t max_join_time
maximum amount of time, in game ticks, a client may take to sync up during joining
uint16_t bytes_per_frame
how many bytes may, over a long period, be received per frame?
uint16_t max_init_time
maximum amount of time, in game ticks, a client may take to initiate joining
uint16_t max_lag_time
maximum amount of time, in game ticks, a client may be lagging behind the server
uint8_t autoclean_novehicles
remove companies with no vehicles after this many months
uint16_t max_commands_in_queue
how many commands may there be in the incoming queue before dropping the connection?
std::string server_name
name of the server
uint16_t restart_hours
number of hours to run the server before automatic restart
uint16_t max_download_time
maximum amount of time, in game ticks, a client may take to download the map
uint16_t sync_freq
how often do we check whether we are still in-sync
std::string rcon_password
password for rconsole (server side)
static void ResetUser(uint32_t user)
Reset an user's OrderBackup if needed.
Writing a savegame directly to a number of packets.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
std::unique_ptr< Packet > current
The packet we're currently writing to.
PacketWriter(ServerNetworkGameSocketHandler *cs)
Create the packet writer.
size_t total_size
Total size of the compressed savegame.
std::condition_variable exit_sig
Signal for threaded destruction of this packet writer.
void Finish() override
Prepare everything to finish writing the savegame.
~PacketWriter() override
Make sure everything is cleaned up.
ServerNetworkGameSocketHandler * cs
Socket we are associated with.
std::mutex mutex
Mutex for making threaded saving safe.
void Destroy()
Begin the destruction of this packet writer.
bool TransferToNetworkQueue()
Transfer all packets from here to the network's queue while holding the lock on our mutex.
std::deque< std::unique_ptr< Packet > > packets
Packet queue of the savegame; send these "slowly" to the client. Cannot be a std::queue as we want to...
Internal entity of a packet.
Definition packet.h:41
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition packet.cpp:362
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
Definition packet.cpp:345
std::string Recv_string(size_t length, StringValidationSettings settings=StringValidationSetting::ReplaceWithQuestionMark)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
Definition packet.cpp:423
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:316
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static T * Create(Targs &&... args)
Creates a new T-object in the associated pool.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
const Tindex index
Index of this pool item.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Interface for filtering a savegame till it is written.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Station data structure.
Vehicle data structure.
@ SPS_CLOSED
The connection got closed.
Definition tcp.h:22
@ Annually
The admin gets information about this on a yearly basis.
@ Weekly
The admin gets information about this on a weekly basis.
@ Monthly
The admin gets information about this on a monthly basis.
@ Quarterly
The admin gets information about this on a quarterly basis.
@ Daily
The admin gets information about this on a daily basis.
@ PACKET_SERVER_JOIN
Tells clients that a new client has joined.
Definition tcp_game.h:84
@ PACKET_SERVER_MAP_SIZE
Server tells the client what the (compressed) size of the map is.
Definition tcp_game.h:79
@ PACKET_SERVER_RCON
Response of the executed command on the server.
Definition tcp_game.h:108
@ PACKET_SERVER_MAP_BEGIN
Server tells the client that it is beginning to send the map.
Definition tcp_game.h:78
@ PACKET_SERVER_SYNC
Server tells the client what the random state should be.
Definition tcp_game.h:95
@ PACKET_SERVER_WAIT
Server tells the client there are some people waiting for the map as well.
Definition tcp_game.h:77
@ PACKET_SERVER_CONFIG_UPDATE
Some network configuration important to the client changed.
Definition tcp_game.h:116
@ PACKET_SERVER_ENABLE_ENCRYPTION
The server tells that authentication has completed and requests to enable encryption with the keys of...
Definition tcp_game.h:62
@ PACKET_SERVER_GAME_INFO
Information about the server.
Definition tcp_game.h:42
@ PACKET_SERVER_ERROR_QUIT
A server tells that a client has hit an error and did quit.
Definition tcp_game.h:122
@ PACKET_SERVER_CLIENT_INFO
Server sends you information about a client.
Definition tcp_game.h:73
@ PACKET_SERVER_WELCOME
Server welcomes you and gives you your ClientID.
Definition tcp_game.h:72
@ PACKET_SERVER_BANNED
The server has banned you.
Definition tcp_game.h:31
@ PACKET_SERVER_FRAME
Server tells the client what frame it is in, and thus to where the client may progress.
Definition tcp_game.h:93
@ PACKET_SERVER_EXTERNAL_CHAT
Server distributing the message from external source.
Definition tcp_game.h:104
@ PACKET_SERVER_CHAT
Server distributing the message of a client (or itself).
Definition tcp_game.h:103
@ PACKET_SERVER_COMMAND
Server distributes a command to (all) the clients.
Definition tcp_game.h:99
@ PACKET_SERVER_SHUTDOWN
The server is shutting down.
Definition tcp_game.h:47
@ PACKET_SERVER_AUTH_REQUEST
The server requests the client to authenticate using a number of methods.
Definition tcp_game.h:60
@ PACKET_SERVER_NEWGAME
The server is preparing to start a new game.
Definition tcp_game.h:46
@ PACKET_SERVER_MOVE
Server tells everyone that someone is moved to another company.
Definition tcp_game.h:112
@ PACKET_SERVER_MAP_DATA
Server sends bits of the map to the client.
Definition tcp_game.h:80
@ PACKET_SERVER_FULL
The server is full and has no place for you.
Definition tcp_game.h:30
@ PACKET_SERVER_QUIT
A server tells that a client has quit.
Definition tcp_game.h:120
@ PACKET_SERVER_ERROR
Server sending an error message to the client.
Definition tcp_game.h:35
@ PACKET_SERVER_CHECK_NEWGRFS
Server sends NewGRF IDs and MD5 checksums for the client to check.
Definition tcp_game.h:68
@ PACKET_SERVER_MAP_DONE
Server tells it has just sent the last bits of the map to the client.
Definition tcp_game.h:81
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
std::mutex lock
synchronization for playback status fields
Definition win32_m.cpp:35
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3300
@ WC_CLIENT_LIST
Client list; Window numbers: