OpenTTD Source 20250312-master-gcdcc6b491d
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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "../strings_func.h"
12#include "core/network_game_info.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 "../safeguards.h"
41
42
43/* This file handles all the server-commands */
44
48
50static_assert(NetworkClientSocketPool::MAX_SIZE > MAX_CLIENTS);
51
54INSTANTIATE_POOL_METHODS(NetworkClientSocket)
55
58
62
63
67 std::unique_ptr<Packet> current;
68 size_t total_size;
69 std::deque<std::unique_ptr<Packet>> packets;
70 std::mutex mutex;
71 std::condition_variable exit_sig;
72
77 PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(nullptr), cs(cs), total_size(0)
78 {
79 }
80
83 {
84 std::unique_lock<std::mutex> lock(this->mutex);
85
86 while (this->cs != nullptr) this->exit_sig.wait(lock);
87
88 /* This must all wait until the Destroy function is called. */
89
90 this->packets.clear();
91 this->current = nullptr;
92 }
93
104 void Destroy()
105 {
106 std::unique_lock<std::mutex> lock(this->mutex);
107
108 this->cs = nullptr;
109
110 this->exit_sig.notify_all();
111 lock.unlock();
112
113 /* Make sure the saving is completely cancelled. Yes,
114 * we need to handle the save finish as well as the
115 * next connection might just be requesting a map. */
116 WaitTillSaved();
117 }
118
125 {
126 /* Unsafe check for the queue being empty or not. */
127 if (this->packets.empty()) return false;
128
129 std::lock_guard<std::mutex> lock(this->mutex);
130
131 while (!this->packets.empty()) {
132 bool last_packet = this->packets.front()->GetPacketType() == PACKET_SERVER_MAP_DONE;
133 this->cs->SendPacket(std::move(this->packets.front()));
134 this->packets.pop_front();
135
136 if (last_packet) return true;
137 }
138
139 return false;
140 }
141
142 void Write(uint8_t *buf, size_t size) override
143 {
144 std::lock_guard<std::mutex> lock(this->mutex);
145
146 /* We want to abort the saving when the socket is closed. */
147 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
148
149 if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
150
151 std::span<const uint8_t> to_write(buf, size);
152 while (!to_write.empty()) {
153 to_write = this->current->Send_bytes(to_write);
154
155 if (!this->current->CanWriteToPacket(1)) {
156 this->packets.push_back(std::move(this->current));
157 if (!to_write.empty()) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
158 }
159 }
160
161 this->total_size += size;
162 }
163
164 void Finish() override
165 {
166 std::lock_guard<std::mutex> lock(this->mutex);
167
168 /* We want to abort the saving when the socket is closed. */
169 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
170
171 /* Make sure the last packet is flushed. */
172 if (this->current != nullptr) this->packets.push_back(std::move(this->current));
173
174 /* Add a packet stating that this is the end to the queue. */
175 this->packets.push_back(std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DONE));
176
177 /* Fast-track the size to the client. */
178 auto p = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_SIZE);
179 p->Send_uint32((uint32_t)this->total_size);
180 this->packets.push_front(std::move(p));
181 }
182};
183
184
190{
193
194 Debug(net, 9, "client[{}] status = INACTIVE", this->client_id);
195
196 /* The Socket and Info pools need to be the same in size. After all,
197 * each Socket will be associated with at most one Info object. As
198 * such if the Socket was allocated the Info object can as well. */
200}
201
206{
207 delete this->GetInfo();
208
211
212 if (this->savegame != nullptr) {
213 this->savegame->Destroy();
214 this->savegame = nullptr;
215 }
216
218}
219
221{
222 /* Only allow receiving when we have some buffer free; this value
223 * can go negative, but eventually it will become positive again. */
224 if (this->receive_limit <= 0) return nullptr;
225
226 /* We can receive a packet, so try that and if needed account for
227 * the amount of received data. */
228 std::unique_ptr<Packet> p = this->NetworkTCPSocketHandler::ReceivePacket();
229 if (p != nullptr) this->receive_limit -= p->Size();
230 return p;
231}
232
234{
236 /*
237 * Sending a message just before leaving the game calls cs->SendPackets.
238 * This might invoke this function, which means that when we close the
239 * connection after cs->SendPackets we will close an already closed
240 * connection. This handles that case gracefully without having to make
241 * that code any more complex or more aware of the validity of the socket.
242 */
243 if (this->IsPendingDeletion() || this->sock == INVALID_SOCKET) return status;
244
246 /* We did not receive a leave message from this client... */
247 std::string client_name = this->GetClientName();
248
249 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
250
251 /* Inform other clients of this... strange leaving ;) */
253 if (new_cs->status >= STATUS_AUTHORIZED && this != new_cs) {
254 new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
255 }
256 }
257 }
258
259 /* If we were transferring a map to this client, stop the savegame creation
260 * process and queue the next client to receive the map. */
261 if (this->status == STATUS_MAP) {
262 /* Ensure the saving of the game is stopped too. */
263 this->savegame->Destroy();
264 this->savegame = nullptr;
265
266 this->CheckNextClientToSendMap(this);
267 }
268
269 NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
270 Debug(net, 3, "[{}] Client #{} closed connection", ServerNetworkGameSocketHandler::GetName(), this->client_id);
271
272 /* We just lost one client :( */
273 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
274 extern uint8_t _network_clients_connected;
276
277 this->SendPackets(true);
278
279 this->DeferDeletion();
280
281 return status;
282}
283
289{
290 extern uint8_t _network_clients_connected;
292
293 /* We can't go over the MAX_CLIENTS limit here. However, the
294 * pool must have place for all clients and ourself. */
297 return accept;
298}
299
302{
304 if (cs->writable) {
305 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
306 /* This client is in the middle of a map-send, call the function for that */
307 cs->SendMap();
308 }
309 }
310 }
311}
312
313static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
314
315/***********
316 * Sending functions
317 ************/
318
324{
325 Debug(net, 9, "client[{}] SendClientInfo(): client_id={}", this->client_id, ci->client_id);
326
327 if (ci->client_id != INVALID_CLIENT_ID) {
328 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CLIENT_INFO);
329 p->Send_uint32(ci->client_id);
330 p->Send_uint8 (ci->client_playas);
331 p->Send_string(ci->client_name);
332 p->Send_string(ci->public_key);
333
334 this->SendPacket(std::move(p));
335 }
337}
338
341{
342 Debug(net, 9, "client[{}] SendGameInfo()", this->client_id);
343
344 auto p = std::make_unique<Packet>(this, PACKET_SERVER_GAME_INFO, TCP_MTU);
345 SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo());
346
347 this->SendPacket(std::move(p));
348
350}
351
358{
359 Debug(net, 9, "client[{}] SendError(): error={}", this->client_id, error);
360
361 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR);
362
363 p->Send_uint8(error);
364 if (!reason.empty()) p->Send_string(reason);
365 this->SendPacket(std::move(p));
366
367 StringID strid = GetNetworkErrorMsg(error);
368
369 /* Only send when the current client was in game */
370 if (this->status >= STATUS_AUTHORIZED) {
371 std::string client_name = this->GetClientName();
372
373 Debug(net, 1, "'{}' made an error and has been disconnected: {}", client_name, GetString(strid));
374
375 if (error == NETWORK_ERROR_KICKED && !reason.empty()) {
376 NetworkTextMessage(NETWORK_ACTION_KICKED, CC_DEFAULT, false, client_name, reason, strid);
377 } else {
378 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
379 }
380
382 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
383 /* Some errors we filter to a more general error. Clients don't have to know the real
384 * reason a joining failed. */
385 if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
386 error = NETWORK_ERROR_ILLEGAL_PACKET;
387 }
388 new_cs->SendErrorQuit(this->client_id, error);
389 }
390 }
391
393 } else {
394 Debug(net, 1, "Client {} made an error and has been disconnected: {}", this->client_id, GetString(strid));
395 }
396
397 /* The client made a mistake, so drop the connection now! */
399}
400
403{
404 Debug(net, 9, "client[{}] SendNewGRFCheck()", this->client_id);
405
406 /* Invalid packet when status is anything but STATUS_IDENTIFY. */
408
409 Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
411
412 if (_grfconfig.empty()) {
413 /* There are no NewGRFs, so they're welcome. */
414 return this->SendWelcome();
415 }
416
417 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
418
419 uint grf_count = std::ranges::count_if(_grfconfig, [](const auto &c){ return !c->flags.Test(GRFConfigFlag::Static); });
420 p->Send_uint8 (grf_count);
421
422 for (const auto &c : _grfconfig) {
423 if (!c->flags.Test(GRFConfigFlag::Static)) SerializeGRFIdentifier(*p, c->ident);
424 }
425
426 this->SendPacket(std::move(p));
428}
429
432{
433 Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
434
435 /* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
437
438 Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
439 this->status = STATUS_AUTH_GAME;
440
441 /* Reset 'lag' counters */
443
444 if (this->authentication_handler == nullptr) {
446 }
447
448 auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST);
449 this->authentication_handler->SendRequest(*p);
450
451 this->SendPacket(std::move(p));
453}
454
457{
458 Debug(net, 9, "client[{}] SendEnableEncryption()", this->client_id);
459
460 /* Invalid packet when status is anything but STATUS_AUTH_GAME. */
462
463 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ENABLE_ENCRYPTION);
464 this->authentication_handler->SendEnableEncryption(*p);
465 this->SendPacket(std::move(p));
467}
468
471{
472 Debug(net, 9, "client[{}] SendWelcome()", this->client_id);
473
474 /* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
476
477 Debug(net, 9, "client[{}] status = AUTHORIZED", this->client_id);
479
480 /* Reset 'lag' counters */
482
483 _network_game_info.clients_on++;
484
485 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WELCOME);
486 p->Send_uint32(this->client_id);
487 this->SendPacket(std::move(p));
488
489 /* Transmit info about all the active clients */
491 if (new_cs != this && new_cs->status >= STATUS_AUTHORIZED) {
492 this->SendClientInfo(new_cs->GetInfo());
493 }
494 }
495 /* Also send the info of the server */
497}
498
501{
502 Debug(net, 9, "client[{}] SendWait()", this->client_id);
503
504 int waiting = 1; // current player getting the map counts as 1
505
506 /* Count how many clients are waiting in the queue, in front of you! */
508 if (new_cs->status != STATUS_MAP_WAIT) continue;
509 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++;
510 }
511
512 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WAIT);
513 p->Send_uint8(waiting);
514 this->SendPacket(std::move(p));
516}
517
518void ServerNetworkGameSocketHandler::CheckNextClientToSendMap(NetworkClientSocket *ignore_cs)
519{
520 Debug(net, 9, "client[{}] CheckNextClientToSendMap()", this->client_id);
521
522 /* Find the best candidate for joining, i.e. the first joiner. */
523 NetworkClientSocket *best = nullptr;
524 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
525 if (ignore_cs == new_cs) continue;
526
527 if (new_cs->status == STATUS_MAP_WAIT) {
528 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)) {
529 best = new_cs;
530 }
531 }
532 }
533
534 /* Is there someone else to join? */
535 if (best != nullptr) {
536 /* Let the first start joining. */
537 best->status = STATUS_AUTHORIZED;
538 best->SendMap();
539
540 /* And update the rest. */
541 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
542 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
543 }
544 }
545}
546
549{
550 if (this->status < STATUS_AUTHORIZED) {
551 /* Illegal call, return error and ignore the packet */
552 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
553 }
554
555 if (this->status == STATUS_AUTHORIZED) {
556 Debug(net, 9, "client[{}] SendMap(): first_packet", this->client_id);
557
558 WaitTillSaved();
559 this->savegame = std::make_shared<PacketWriter>(this);
560
561 /* Now send the _frame_counter and how many packets are coming */
562 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MAP_BEGIN);
563 p->Send_uint32(_frame_counter);
564 this->SendPacket(std::move(p));
565
567 Debug(net, 9, "client[{}] status = MAP", this->client_id);
568 this->status = STATUS_MAP;
569 /* Mark the start of download */
572
573 /* Make a dump of the current game */
574 if (SaveWithFilter(this->savegame, true) != SL_OK) UserError("network savedump failed");
575 }
576
577 if (this->status == STATUS_MAP) {
578 bool last_packet = this->savegame->TransferToNetworkQueue();
579 if (last_packet) {
580 Debug(net, 9, "client[{}] SendMap(): last_packet", this->client_id);
581
582 /* Done reading, make sure saving is done as well */
583 this->savegame->Destroy();
584 this->savegame = nullptr;
585
586 /* Set the status to DONE_MAP, no we will wait for the client
587 * to send it is ready (maybe that happens like never ;)) */
588 Debug(net, 9, "client[{}] status = DONE_MAP", this->client_id);
589 this->status = STATUS_DONE_MAP;
590
591 this->CheckNextClientToSendMap();
592 }
593 }
595}
596
602{
603 Debug(net, 9, "client[{}] SendJoin(): client_id={}", this->client_id, client_id);
604
605 auto p = std::make_unique<Packet>(this, PACKET_SERVER_JOIN);
606
607 p->Send_uint32(client_id);
608
609 this->SendPacket(std::move(p));
611}
612
615{
616 auto p = std::make_unique<Packet>(this, PACKET_SERVER_FRAME);
617 p->Send_uint32(_frame_counter);
618 p->Send_uint32(_frame_counter_max);
619#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
620 p->Send_uint32(_sync_seed_1);
621#ifdef NETWORK_SEND_DOUBLE_SEED
622 p->Send_uint32(_sync_seed_2);
623#endif
624#endif
625
626 /* If token equals 0, we need to make a new token and send that. */
627 if (this->last_token == 0) {
628 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
629 p->Send_uint8(this->last_token);
630 }
631
632 this->SendPacket(std::move(p));
634}
635
638{
639 Debug(net, 9, "client[{}] SendSync(), frame_counter={}, sync_seed_1={}", this->client_id, _frame_counter, _sync_seed_1);
640
641 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SYNC);
642 p->Send_uint32(_frame_counter);
643 p->Send_uint32(_sync_seed_1);
644
645#ifdef NETWORK_SEND_DOUBLE_SEED
646 p->Send_uint32(_sync_seed_2);
647#endif
648 this->SendPacket(std::move(p));
650}
651
657{
658 Debug(net, 9, "client[{}] SendCommand(): cmd={}", this->client_id, cp.cmd);
659
660 auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMMAND);
661
663 p->Send_uint32(cp.frame);
664 p->Send_bool (cp.my_cmd);
665
666 this->SendPacket(std::move(p));
668}
669
678NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64_t data)
679{
680 Debug(net, 9, "client[{}] SendChat(): action={}, client_id={}, self_send={}", this->client_id, action, client_id, self_send);
681
683
684 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHAT);
685
686 p->Send_uint8 (action);
687 p->Send_uint32(client_id);
688 p->Send_bool (self_send);
689 p->Send_string(msg);
690 p->Send_uint64(data);
691
692 this->SendPacket(std::move(p));
694}
695
703NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
704{
705 Debug(net, 9, "client[{}] SendExternalChat(): source={}", this->client_id, source);
706
708
709 auto p = std::make_unique<Packet>(this, PACKET_SERVER_EXTERNAL_CHAT);
710
711 p->Send_string(source);
712 p->Send_uint16(colour);
713 p->Send_string(user);
714 p->Send_string(msg);
715
716 this->SendPacket(std::move(p));
718}
719
726{
727 Debug(net, 9, "client[{}] SendErrorQuit(): client_id={}, errorno={}", this->client_id, client_id, errorno);
728
729 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR_QUIT);
730
731 p->Send_uint32(client_id);
732 p->Send_uint8 (errorno);
733
734 this->SendPacket(std::move(p));
736}
737
743{
744 Debug(net, 9, "client[{}] SendQuit(): client_id={}", this->client_id, client_id);
745
746 auto p = std::make_unique<Packet>(this, PACKET_SERVER_QUIT);
747
748 p->Send_uint32(client_id);
749
750 this->SendPacket(std::move(p));
752}
753
756{
757 Debug(net, 9, "client[{}] SendShutdown()", this->client_id);
758
759 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SHUTDOWN);
760 this->SendPacket(std::move(p));
762}
763
766{
767 Debug(net, 9, "client[{}] SendNewGame()", this->client_id);
768
769 auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEWGAME);
770 this->SendPacket(std::move(p));
772}
773
779NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour, const std::string &command)
780{
781 Debug(net, 9, "client[{}] SendRConResult()", this->client_id);
782
783 auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON);
784
785 p->Send_uint16(colour);
786 p->Send_string(command);
787 this->SendPacket(std::move(p));
789}
790
797{
798 Debug(net, 9, "client[{}] SendMove(): client_id={}", this->client_id, client_id);
799
800 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MOVE);
801
802 p->Send_uint32(client_id);
803 p->Send_uint8(company_id);
804 this->SendPacket(std::move(p));
806}
807
810{
811 Debug(net, 9, "client[{}] SendConfigUpdate()", this->client_id);
812
813 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CONFIG_UPDATE);
814
816 p->Send_string(_settings_client.network.server_name);
817 this->SendPacket(std::move(p));
819}
820
821/***********
822 * Receiving functions
823 ************/
824
826{
827 Debug(net, 9, "client[{}] Receive_CLIENT_GAME_INFO()", this->client_id);
828
829 return this->SendGameInfo();
830}
831
833{
834 if (this->status != STATUS_NEWGRFS_CHECK) {
835 /* Illegal call, return error and ignore the packet */
836 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
837 }
838
839 Debug(net, 9, "client[{}] Receive_CLIENT_NEWGRFS_CHECKED()", this->client_id);
840
841 return this->SendWelcome();
842}
843
845{
846 if (this->status != STATUS_INACTIVE) {
847 /* Illegal call, return error and ignore the packet */
848 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
849 }
850
851 if (_network_game_info.clients_on >= _settings_client.network.max_clients) {
852 /* Turns out we are full. Inform the user about this. */
853 return this->SendError(NETWORK_ERROR_FULL);
854 }
855
856 std::string client_revision = p.Recv_string(NETWORK_REVISION_LENGTH);
857 uint32_t newgrf_version = p.Recv_uint32();
858
859 Debug(net, 9, "client[{}] Receive_CLIENT_JOIN(): client_revision={}, newgrf_version={}", this->client_id, client_revision, newgrf_version);
860
861 /* Check if the client has revision control enabled */
862 if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
863 /* Different revisions!! */
864 return this->SendError(NETWORK_ERROR_WRONG_REVISION);
865 }
866
867 return this->SendAuthRequest();
868}
869
871{
872 if (this->status != STATUS_IDENTIFY) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
873
874 Debug(net, 9, "client[{}] Receive_CLIENT_IDENTIFY()", this->client_id);
875
876 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
877 CompanyID playas = (Owner)p.Recv_uint8();
878
880
881 /* join another company does not affect these values */
882 switch (playas.base()) {
883 case COMPANY_NEW_COMPANY.base(): // New company
885 return this->SendError(NETWORK_ERROR_FULL);
886 }
887 break;
888 case COMPANY_SPECTATOR.base(): // Spectator
889 break;
890 default: // Join another company (companies 1..MAX_COMPANIES (index 0..(MAX_COMPANIES-1)))
891 if (!Company::IsValidHumanID(playas)) {
892 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
893 }
894
895 if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) {
896 /* When we're not authorized, just bump us to a spectator. */
897 playas = COMPANY_SPECTATOR;
898 }
899 break;
900 }
901
902 if (!NetworkIsValidClientName(client_name)) {
903 /* An invalid client name was given. However, the client ensures the name
904 * is valid before it is sent over the network, so something went horribly
905 * wrong. This is probably someone trying to troll us. */
906 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
907 }
908
909 if (!NetworkMakeClientNameUnique(client_name)) { // Change name if duplicate
910 /* We could not create a name for this client */
911 return this->SendError(NETWORK_ERROR_NAME_IN_USE);
912 }
913
916 this->SetInfo(ci);
918 ci->client_name = client_name;
919 ci->client_playas = playas;
920 ci->public_key = this->peer_public_key;
921 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, ci->index);
922
923 /* Make sure companies to which people try to join are not autocleaned */
924 Company *c = Company::GetIfValid(playas);
925 if (c != nullptr) c->months_empty = 0;
926
927 return this->SendNewGRFCheck();
928}
929
930static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
931{
932 switch (method) {
934 return NETWORK_ERROR_WRONG_PASSWORD;
936 return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
937
938 default:
939 NOT_REACHED();
940 }
941}
942
944{
945 if (this->status != STATUS_AUTH_GAME) {
946 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
947 }
948
949 Debug(net, 9, "client[{}] Receive_CLIENT_AUTH_RESPONSE()", this->client_id);
950
951 auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
952 switch (this->authentication_handler->ReceiveResponse(p)) {
954 break;
955
957 return this->SendAuthRequest();
958
960 default:
961 return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
962 }
963
965 if (status != NETWORK_RECV_STATUS_OKAY) return status;
966
967 this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
968 this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
969 this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
970 this->authentication_handler = nullptr;
971
972 Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
973 this->status = STATUS_IDENTIFY;
974
975 /* Reset 'lag' counters */
977
979}
980
982{
983 /* The client was never joined.. so this is impossible, right?
984 * Ignore the packet, give the client a warning, and close the connection */
985 if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
986 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
987 }
988
989 Debug(net, 9, "client[{}] Receive_CLIENT_GETMAP()", this->client_id);
990
991 /* Check if someone else is receiving the map */
993 if (new_cs->status == STATUS_MAP) {
994 /* Tell the new client to wait */
995 Debug(net, 9, "client[{}] status = MAP_WAIT", this->client_id);
996 this->status = STATUS_MAP_WAIT;
997 return this->SendWait();
998 }
999 }
1000
1001 /* We receive a request to upload the map.. give it to the client! */
1002 return this->SendMap();
1003}
1004
1006{
1007 /* Client has the map, now start syncing */
1008 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
1009 Debug(net, 9, "client[{}] Receive_CLIENT_MAP_OK()", this->client_id);
1010
1011 std::string client_name = this->GetClientName();
1012
1013 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id);
1015
1016 Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name);
1017
1018 /* Mark the client as pre-active, and wait for an ACK
1019 * so we know it is done loading and in sync with us */
1020 Debug(net, 9, "client[{}] status = PRE_ACTIVE", this->client_id);
1021 this->status = STATUS_PRE_ACTIVE;
1023 this->SendFrame();
1024 this->SendSync();
1025
1026 /* This is the frame the client receives
1027 * we need it later on to make sure the client is not too slow */
1028 this->last_frame = _frame_counter;
1030
1032 if (new_cs->status >= STATUS_AUTHORIZED) {
1033 new_cs->SendClientInfo(this->GetInfo());
1034 new_cs->SendJoin(this->client_id);
1035 }
1036 }
1037
1038 NetworkAdminClientInfo(this, true);
1039
1040 /* also update the new client with our max values */
1041 return this->SendConfigUpdate();
1042 }
1043
1044 /* Wrong status for this packet, give a warning to client, and close connection */
1045 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1046}
1047
1053{
1054 /* The client was never joined.. so this is impossible, right?
1055 * Ignore the packet, give the client a warning, and close the connection */
1056 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1057 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1058 }
1059
1061 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
1062 }
1063
1064 Debug(net, 9, "client[{}] Receive_CLIENT_COMMAND()", this->client_id);
1065
1066 CommandPacket cp;
1067 const char *err = this->ReceiveCommand(p, cp);
1068
1070
1071 NetworkClientInfo *ci = this->GetInfo();
1072
1073 if (err != nullptr) {
1074 IConsolePrint(CC_WARNING, "Dropping client #{} (IP: {}) due to {}.", ci->client_id, this->GetClientIP(), err);
1075 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1076 }
1077
1078
1080 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a server only command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1081 return this->SendError(NETWORK_ERROR_KICKED);
1082 }
1083
1085 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a non-spectator command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1086 return this->SendError(NETWORK_ERROR_KICKED);
1087 }
1088
1094 CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : CCA_NEW;
1095 if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
1096 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
1097 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1098 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
1099 }
1100
1101 if (cp.cmd == CMD_COMPANY_CTRL) {
1102 if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) {
1103 return this->SendError(NETWORK_ERROR_CHEATER);
1104 }
1105
1106 /* 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! */
1108 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
1110 }
1111 }
1112
1113 if (cp.cmd == CMD_COMPANY_ALLOW_LIST_CTRL) {
1114 /* Maybe the client just got moved before allowing? */
1116
1117 /* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
1118 std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_ALLOW_LIST_CTRL>::Args>(cp.data));
1119 bool found = false;
1121 if (info->public_key == public_key) {
1122 found = true;
1123 break;
1124 }
1125 }
1126
1127 /* Maybe the client just left? */
1128 if (!found) return NETWORK_RECV_STATUS_OKAY;
1129 }
1130
1132
1133 this->incoming_queue.push_back(cp);
1135}
1136
1138{
1139 /* This packets means a client noticed an error and is reporting this
1140 * to us. Display the error and report it to the other clients */
1142
1143 Debug(net, 9, "client[{}] Receive_CLIENT_ERROR(): errorno={}", this->client_id, errorno);
1144
1145 /* The client was never joined.. thank the client for the packet, but ignore it */
1146 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1148 }
1149
1150 std::string client_name = this->GetClientName();
1151 StringID strid = GetNetworkErrorMsg(errorno);
1152
1153 Debug(net, 1, "'{}' reported an error and is closing its connection: {}", client_name, GetString(strid));
1154
1155 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
1156
1158 if (new_cs->status >= STATUS_AUTHORIZED) {
1159 new_cs->SendErrorQuit(this->client_id, errorno);
1160 }
1161 }
1162
1163 NetworkAdminClientError(this->client_id, errorno);
1164
1166}
1167
1169{
1170 /* The client was never joined.. thank the client for the packet, but ignore it */
1171 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1173 }
1174
1175 Debug(net, 9, "client[{}] Receive_CLIENT_QUIT()", this->client_id);
1176
1177 /* The client wants to leave. Display this and report it to the other clients. */
1178 std::string client_name = this->GetClientName();
1179 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1180
1182 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
1183 new_cs->SendQuit(this->client_id);
1184 }
1185 }
1186
1188
1190}
1191
1193{
1194 if (this->status < STATUS_AUTHORIZED) {
1195 /* Illegal call, return error and ignore the packet */
1196 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1197 }
1198
1199 uint32_t frame = p.Recv_uint32();
1200
1201 Debug(net, 9, "client[{}] Receive_CLIENT_ACK(): frame={}", this->client_id, frame);
1202
1203 /* The client is trying to catch up with the server */
1204 if (this->status == STATUS_PRE_ACTIVE) {
1205 /* The client is not yet caught up? */
1207
1208 /* Now it is! Unpause the game */
1209 Debug(net, 9, "client[{}] status = ACTIVE", this->client_id);
1210 this->status = STATUS_ACTIVE;
1212
1213 /* Execute script for, e.g. MOTD */
1214 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
1215 }
1216
1217 /* Get, and validate the token. */
1218 uint8_t token = p.Recv_uint8();
1219 if (token == this->last_token) {
1220 /* We differentiate between last_token_frame and last_frame so the lag
1221 * test uses the actual lag of the client instead of the lag for getting
1222 * the token back and forth; after all, the token is only sent every
1223 * time we receive a PACKET_CLIENT_ACK, after which we will send a new
1224 * token to the client. If the lag would be one day, then we would not
1225 * be sending the new token soon enough for the new daily scheduled
1226 * PACKET_CLIENT_ACK. This would then register the lag of the client as
1227 * two days, even when it's only a single day. */
1229 /* Request a new token. */
1230 this->last_token = 0;
1231 }
1232
1233 /* The client received the frame, make note of it */
1234 this->last_frame = frame;
1235 /* With those 2 values we can calculate the lag realtime */
1238}
1239
1240
1251void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const std::string &msg, ClientID from_id, int64_t data, bool from_admin)
1252{
1253 const NetworkClientInfo *ci, *ci_own, *ci_to;
1254
1255 switch (desttype) {
1256 case DESTTYPE_CLIENT:
1257 /* Are we sending to the server? */
1258 if ((ClientID)dest == CLIENT_ID_SERVER) {
1260 /* Display the text locally, and that is it */
1261 if (ci != nullptr) {
1262 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1263
1265 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1266 }
1267 }
1268 } else {
1269 /* Else find the client to send the message to */
1270 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1271 if (cs->client_id == (ClientID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1272 cs->SendChat(action, from_id, false, msg, data);
1273 break;
1274 }
1275 }
1276 }
1277
1278 /* Display the message locally (so you know you have sent it) */
1279 if (from_id != (ClientID)dest) {
1280 if (from_id == CLIENT_ID_SERVER) {
1283 if (ci != nullptr && ci_to != nullptr) {
1284 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
1285 }
1286 } else {
1287 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1288 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1289 cs->SendChat(action, (ClientID)dest, true, msg, data);
1290 break;
1291 }
1292 }
1293 }
1294 }
1295 break;
1296 case DESTTYPE_TEAM: {
1297 /* If this is false, the message is already displayed on the client who sent it. */
1298 bool show_local = true;
1299 /* Find all clients that belong to this company */
1300 ci_to = nullptr;
1301 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1302 ci = cs->GetInfo();
1303 if (ci != nullptr && ci->client_playas == (CompanyID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1304 cs->SendChat(action, from_id, false, msg, data);
1305 if (cs->client_id == from_id) show_local = false;
1306 ci_to = ci; // Remember a client that is in the company for company-name
1307 }
1308 }
1309
1310 /* if the server can read it, let the admin network read it, too. */
1312 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1313 }
1314
1317 if (ci != nullptr && ci_own != nullptr && ci_own->client_playas == dest) {
1318 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1319 if (from_id == CLIENT_ID_SERVER) show_local = false;
1320 ci_to = ci_own;
1321 }
1322
1323 /* There is no such client */
1324 if (ci_to == nullptr) break;
1325
1326 /* Display the message locally (so you know you have sent it) */
1327 if (ci != nullptr && show_local) {
1328 if (from_id == CLIENT_ID_SERVER) {
1329 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1330 std::string name = GetString(str, ci_to->client_playas);
1331 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
1332 } else {
1333 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1334 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1335 cs->SendChat(action, ci_to->client_id, true, msg, data);
1336 }
1337 }
1338 }
1339 }
1340 break;
1341 }
1342 default:
1343 Debug(net, 1, "Received unknown chat destination type {}; doing broadcast instead", desttype);
1344 [[fallthrough]];
1345
1346 case DESTTYPE_BROADCAST:
1347 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1348 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendChat(action, from_id, false, msg, data);
1349 }
1350
1351 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1352
1354 if (ci != nullptr) {
1355 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1356 }
1357 break;
1358 }
1359}
1360
1368void NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
1369{
1370 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1371 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendExternalChat(source, colour, user, msg);
1372 }
1373 NetworkTextMessage(NETWORK_ACTION_EXTERNAL_CHAT, colour, false, user, msg, source);
1374}
1375
1377{
1378 if (this->status < STATUS_PRE_ACTIVE) {
1379 /* Illegal call, return error and ignore the packet */
1380 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1381 }
1382
1384 DestType desttype = (DestType)p.Recv_uint8();
1385 int dest = p.Recv_uint32();
1386
1387 Debug(net, 9, "client[{}] Receive_CLIENT_CHAT(): action={}, desttype={}, dest={}", this->client_id, action, desttype, dest);
1388
1389 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1390 int64_t data = p.Recv_uint64();
1391
1392 NetworkClientInfo *ci = this->GetInfo();
1393 switch (action) {
1394 case NETWORK_ACTION_CHAT:
1395 case NETWORK_ACTION_CHAT_CLIENT:
1396 case NETWORK_ACTION_CHAT_COMPANY:
1397 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
1398 break;
1399 default:
1400 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to unknown chact action.", ci->client_id, this->GetClientIP());
1401 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1402 }
1404}
1405
1407{
1408 if (this->status != STATUS_ACTIVE) {
1409 /* Illegal call, return error and ignore the packet */
1410 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1411 }
1412
1413 Debug(net, 9, "client[{}] Receive_CLIENT_SET_NAME()", this->client_id);
1414
1416
1417 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
1418 ci = this->GetInfo();
1419
1421
1422 if (ci != nullptr) {
1423 if (!NetworkIsValidClientName(client_name)) {
1424 /* An invalid client name was given. However, the client ensures the name
1425 * is valid before it is sent over the network, so something went horribly
1426 * wrong. This is probably someone trying to troll us. */
1427 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
1428 }
1429
1430 /* Display change */
1431 if (NetworkMakeClientNameUnique(client_name)) {
1432 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
1433 ci->client_name = client_name;
1435 }
1436 }
1438}
1439
1441{
1442 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1443
1444 Debug(net, 9, "client[{}] Receive_CLIENT_RCON()", this->client_id);
1445
1446 std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
1447 std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1448
1449 if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
1450 /* We are allowed, nothing more to validate. */
1451 } else if (_settings_client.network.rcon_password.empty()) {
1453 } else if (_settings_client.network.rcon_password.compare(password) != 0) {
1454 Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id);
1456 }
1457
1458 Debug(net, 3, "[rcon] Client-id {} executed: {}", this->client_id, command);
1459
1461 IConsoleCmdExec(command);
1464}
1465
1467{
1468 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1469
1470 CompanyID company_id = (Owner)p.Recv_uint8();
1471
1472 Debug(net, 9, "client[{}] Receive_CLIENT_MOVE(): company_id={}", this->client_id, company_id);
1473
1474 /* Check if the company is valid, we don't allow moving to AI companies */
1475 if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
1476
1477 if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) {
1478 Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
1480 }
1481
1482 /* if we get here we can move the client */
1483 NetworkServerDoMove(this->client_id, company_id);
1485}
1486
1491{
1492 NetworkCompanyStatsArray stats = {};
1493
1494 /* Go through all vehicles and count the type of vehicles */
1495 for (const Vehicle *v : Vehicle::Iterate()) {
1496 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1497 uint8_t type = 0;
1498 switch (v->type) {
1499 case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
1500 case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
1501 case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
1502 case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
1503 default: continue;
1504 }
1505 stats[v->owner].num_vehicle[type]++;
1506 }
1507
1508 /* Go through all stations and count the types of stations */
1509 for (const Station *s : Station::Iterate()) {
1510 if (Company::IsValidID(s->owner)) {
1511 NetworkCompanyStats *npi = &stats[s->owner];
1512
1513 if (s->facilities.Test(StationFacility::Train)) npi->num_station[NETWORK_VEH_TRAIN]++;
1514 if (s->facilities.Test(StationFacility::TruckStop)) npi->num_station[NETWORK_VEH_LORRY]++;
1515 if (s->facilities.Test(StationFacility::BusStop)) npi->num_station[NETWORK_VEH_BUS]++;
1516 if (s->facilities.Test(StationFacility::Airport)) npi->num_station[NETWORK_VEH_PLANE]++;
1517 if (s->facilities.Test(StationFacility::Dock)) npi->num_station[NETWORK_VEH_SHIP]++;
1518 }
1519 }
1520
1521 return stats;
1522}
1523
1529{
1531
1532 if (ci == nullptr) return;
1533
1534 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, client_id);
1535
1536 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1538 cs->SendClientInfo(ci);
1539 }
1540 }
1541
1543}
1544
1551{
1552 CompanyMask has_clients{};
1553 CompanyMask has_vehicles{};
1554
1556
1557 /* Detect the active companies */
1558 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1559 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1560 }
1561
1562 if (!_network_dedicated) {
1564 assert(ci != nullptr);
1565 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1566 }
1567
1569 for (const Company *c : Company::Iterate()) {
1570 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);
1571 }
1572 }
1573
1574 /* Go through all the companies */
1575 for (Company *c : Company::Iterate()) {
1576 /* Skip the non-active once */
1577 if (c->is_ai) continue;
1578
1579 if (!has_clients.Test(c->index)) {
1580 /* The company is empty for one month more */
1581 if (c->months_empty != std::numeric_limits<decltype(c->months_empty)>::max()) c->months_empty++;
1582
1583 /* Is the company empty for autoclean_protected-months? */
1585 /* Shut the company down */
1587 IConsolePrint(CC_INFO, "Auto-cleaned company #{}.", c->index + 1);
1588 }
1589 /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
1590 if (_settings_client.network.autoclean_novehicles != 0 && c->months_empty > _settings_client.network.autoclean_novehicles && !has_vehicles.Test(c->index)) {
1591 /* Shut the company down */
1593 IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
1594 }
1595 } else {
1596 /* It is not empty, reset the date */
1597 c->months_empty = 0;
1598 }
1599 }
1600}
1601
1607bool NetworkMakeClientNameUnique(std::string &name)
1608{
1609 bool is_name_unique = false;
1610 std::string original_name = name;
1611
1612 for (uint number = 1; !is_name_unique && number <= MAX_CLIENTS; number++) { // Something's really wrong when there're more names than clients
1613 is_name_unique = true;
1614 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1615 if (ci->client_name == name) {
1616 /* Name already in use */
1617 is_name_unique = false;
1618 break;
1619 }
1620 }
1621 /* Check if it is the same as the server-name */
1623 if (ci != nullptr) {
1624 if (ci->client_name == name) is_name_unique = false; // name already in use
1625 }
1626
1627 if (!is_name_unique) {
1628 /* Try a new name (<name> #1, <name> #2, and so on) */
1629 name = original_name + " #" + std::to_string(number);
1630
1631 /* The constructed client name is larger than the limit,
1632 * so... bail out as no valid name can be created. */
1633 if (name.size() >= NETWORK_CLIENT_NAME_LENGTH) return false;
1634 }
1635 }
1636
1637 return is_name_unique;
1638}
1639
1646bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
1647{
1648 /* Check if the name's already in use */
1650 if (ci->client_name.compare(new_name) == 0) return false;
1651 }
1652
1654 if (ci == nullptr) return false;
1655
1656 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
1657
1658 ci->client_name = new_name;
1659
1660 NetworkUpdateClientInfo(client_id);
1661 return true;
1662}
1663
1668static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
1669{
1670 for (auto &cp : cs->outgoing_queue) cs->SendCommand(cp);
1671 cs->outgoing_queue.clear();
1672}
1673
1678void NetworkServer_Tick(bool send_frame)
1679{
1680#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1681 bool send_sync = false;
1682#endif
1683
1684#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1687 send_sync = true;
1688 }
1689#endif
1690
1691 /* Now we are done with the frame, inform the clients that they can
1692 * do their frame! */
1693 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1694 /* We allow a number of bytes per frame, but only to the burst amount
1695 * to be available for packet receiving at any particular time. */
1696 cs->receive_limit = std::min<size_t>(cs->receive_limit + _settings_client.network.bytes_per_frame,
1698
1699 /* Check if the speed of the client is what we can expect from a client */
1700 uint lag = NetworkCalculateLag(cs);
1701 switch (cs->status) {
1702 case NetworkClientSocket::STATUS_ACTIVE:
1704 /* Client did still not report in within the specified limit. */
1705
1706 if (cs->last_packet + std::chrono::milliseconds(lag * MILLISECONDS_PER_TICK) > std::chrono::steady_clock::now()) {
1707 /* A packet was received in the last three game days, so the client is likely lagging behind. */
1708 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client's game state is more than {} ticks behind.", cs->client_id, cs->GetClientIP(), lag);
1709 } else {
1710 /* No packet was received in the last three game days; sounds like a lost connection. */
1711 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client did not respond for more than {} ticks.", cs->client_id, cs->GetClientIP(), lag);
1712 }
1713 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1714 continue;
1715 }
1716
1717 /* Report once per time we detect the lag, and only when we
1718 * received a packet in the last 2 seconds. If we
1719 * did not receive a packet, then the client is not just
1720 * slow, but the connection is likely severed. Mentioning
1721 * frame_freq is not useful in this case. */
1722 if (lag > (uint)Ticks::DAY_TICKS && cs->lag_test == 0 && cs->last_packet + std::chrono::seconds(2) > std::chrono::steady_clock::now()) {
1723 IConsolePrint(CC_WARNING, "[{}] Client #{} is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
1724 cs->lag_test = 1;
1725 }
1726
1727 if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) {
1728 /* This is a bad client! It didn't send the right token back within time. */
1729 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it fails to send valid acks.", cs->client_id, cs->GetClientIP());
1730 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1731 continue;
1732 }
1733 break;
1734
1735 case NetworkClientSocket::STATUS_INACTIVE:
1736 case NetworkClientSocket::STATUS_IDENTIFY:
1737 case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
1738 case NetworkClientSocket::STATUS_AUTHORIZED:
1739 /* NewGRF check and authorized states should be handled almost instantly.
1740 * So give them some lee-way, likewise for the query with inactive. */
1742 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);
1743 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1744 continue;
1745 }
1746 break;
1747
1748 case NetworkClientSocket::STATUS_MAP_WAIT:
1749 /* Send every two seconds a packet to the client, to make sure
1750 * it knows the server is still there; just someone else is
1751 * still receiving the map. */
1752 if (std::chrono::steady_clock::now() > cs->last_packet + std::chrono::seconds(2)) {
1753 cs->SendWait();
1754 /* We need to reset the timer, as otherwise we will be
1755 * spamming the client. Strictly speaking this variable
1756 * tracks when we last received a packet from the client,
1757 * but as it is waiting, it will not send us any till we
1758 * start sending them data. */
1759 cs->last_packet = std::chrono::steady_clock::now();
1760 }
1761 break;
1762
1763 case NetworkClientSocket::STATUS_MAP:
1764 /* Downloading the map... this is the amount of time since starting the saving. */
1766 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);
1767 cs->SendError(NETWORK_ERROR_TIMEOUT_MAP);
1768 continue;
1769 }
1770 break;
1771
1772 case NetworkClientSocket::STATUS_DONE_MAP:
1773 case NetworkClientSocket::STATUS_PRE_ACTIVE:
1774 /* The map has been sent, so this is for loading the map and syncing up. */
1776 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);
1777 cs->SendError(NETWORK_ERROR_TIMEOUT_JOIN);
1778 continue;
1779 }
1780 break;
1781
1782 case NetworkClientSocket::STATUS_AUTH_GAME:
1783 /* These don't block? */
1785 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);
1786 cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD);
1787 continue;
1788 }
1789 break;
1790
1791 case NetworkClientSocket::STATUS_END:
1792 /* Bad server/code. */
1793 NOT_REACHED();
1794 }
1795
1796 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
1797 /* Check if we can send command, and if we have anything in the queue */
1799
1800 /* Send an updated _frame_counter_max to the client */
1801 if (send_frame) cs->SendFrame();
1802
1803#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1804 /* Send a sync-check packet */
1805 if (send_sync) cs->SendSync();
1806#endif
1807 }
1808 }
1809}
1810
1813{
1816 case FT_SAVEGAME:
1817 case FT_SCENARIO:
1819 break;
1820
1821 case FT_HEIGHTMAP:
1823 break;
1824
1825 default:
1827 }
1828}
1829
1832{
1833 if (!_network_server) return;
1834
1835 /* If setting is 0, this feature is disabled. */
1836 if (_settings_client.network.restart_hours == 0) return;
1837
1838 Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);
1840});
1841
1847{
1848 if (!_network_server) return;
1849
1851}
1852
1855{
1856 /* If setting is 0, this feature is disabled. */
1858
1860 Debug(net, 3, "Auto-restarting map: year {} reached", TimerGameCalendar::year);
1862 }
1863}
1864
1866static IntervalTimer<TimerGameCalendar> _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) {
1867 if (!_network_server) return;
1868
1870});
1871
1873static IntervalTimer<TimerGameEconomy> _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto)
1874{
1875 if (!_network_server) return;
1876
1878});
1879
1881static IntervalTimer<TimerGameEconomy> _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto)
1882{
1883 if (!_network_server) return;
1884
1887});
1888
1890static IntervalTimer<TimerGameEconomy> _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto)
1891{
1892 if (!_network_server) return;
1893
1896});
1897
1899static IntervalTimer<TimerGameEconomy> _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto)
1900{
1901 if (!_network_server) return;
1902
1904});
1905
1907static IntervalTimer<TimerGameEconomy> _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto)
1908{
1909 if (!_network_server) return;
1910
1912});
1913
1919{
1920 return this->client_address.GetHostname();
1921}
1922
1925{
1926 static const char * const stat_str[] = {
1927 "inactive",
1928 "authorizing",
1929 "identifying client",
1930 "checking NewGRFs",
1931 "authorized",
1932 "waiting",
1933 "loading map",
1934 "map done",
1935 "ready",
1936 "active"
1937 };
1938 static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
1939
1940 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1941 NetworkClientInfo *ci = cs->GetInfo();
1942 if (ci == nullptr) continue;
1943 uint lag = NetworkCalculateLag(cs);
1944 const char *status;
1945
1946 status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
1947 IConsolePrint(CC_INFO, "Client #{} name: '{}' status: '{}' frame-lag: {} company: {} IP: {}",
1948 cs->client_id, ci->client_name, status, lag,
1949 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
1950 cs->GetClientIP());
1951 }
1952}
1953
1958{
1959 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1960 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
1961 }
1962}
1963
1966{
1967 if (_network_server) FillStaticNetworkServerGameInfo();
1968}
1969
1976void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
1977{
1978 /* Only allow non-dedicated servers and normal clients to be moved */
1979 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
1980
1982 assert(ci != nullptr);
1983
1984 /* No need to waste network resources if the client is in the company already! */
1985 if (ci->client_playas == company_id) return;
1986
1987 ci->client_playas = company_id;
1988
1989 if (client_id == CLIENT_ID_SERVER) {
1990 SetLocalCompany(company_id);
1991 } else {
1992 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
1993 /* When the company isn't authorized we can't move them yet. */
1994 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
1995 cs->SendMove(client_id, company_id);
1996 }
1997
1998 /* Announce the client's move. */
1999 NetworkUpdateClientInfo(client_id);
2000
2001 if (company_id == COMPANY_SPECTATOR) {
2002 /* The client has joined spectators. */
2003 NetworkServerSendChat(NETWORK_ACTION_COMPANY_SPECTATOR, DESTTYPE_BROADCAST, 0, "", client_id);
2004 } else {
2005 /* The client has joined another company. */
2006 std::string company_name = GetString(STR_COMPANY_NAME, company_id);
2007 NetworkServerSendChat(NETWORK_ACTION_COMPANY_JOIN, DESTTYPE_BROADCAST, 0, company_name, client_id);
2008 }
2009
2011}
2012
2019void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string)
2020{
2021 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
2022}
2023
2029void NetworkServerKickClient(ClientID client_id, const std::string &reason)
2030{
2031 if (client_id == CLIENT_ID_SERVER) return;
2032 NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED, reason);
2033}
2034
2041uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
2042{
2043 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban, reason);
2044}
2045
2052uint NetworkServerKickOrBanIP(const std::string &ip, bool ban, const std::string &reason)
2053{
2054 /* Add address to ban-list */
2055 if (ban) {
2056 bool contains = false;
2057 for (const auto &iter : _network_ban_list) {
2058 if (iter == ip) {
2059 contains = true;
2060 break;
2061 }
2062 }
2063 if (!contains) _network_ban_list.emplace_back(ip);
2064 }
2065
2066 uint n = 0;
2067
2068 /* There can be multiple clients with the same IP, kick them all but don't kill the server,
2069 * or the client doing the rcon. The latter can't be kicked because kicking frees closes
2070 * and subsequently free the connection related instances, which we would be reading from
2071 * and writing to after returning. So we would read or write data from freed memory up till
2072 * the segfault triggers. */
2073 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2074 if (cs->client_id == CLIENT_ID_SERVER) continue;
2075 if (cs->client_id == _redirect_console_to_client) continue;
2076 if (cs->client_address.IsInNetmask(ip)) {
2077 NetworkServerKickClient(cs->client_id, reason);
2078 n++;
2079 }
2080 }
2081
2082 return n;
2083}
2084
2091{
2092 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
2093 if (ci->client_playas == company) return true;
2094 }
2095 return false;
2096}
2097
2098
2105{
2106 const NetworkClientInfo *ci = this->GetInfo();
2107 if (ci != nullptr && !ci->client_name.empty()) return ci->client_name;
2108
2109 return fmt::format("Client #{}", this->client_id);
2110}
2111
2116{
2118 if (_network_server) {
2119 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {} IP: {}",
2120 ci->client_id,
2121 ci->client_name,
2122 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2123 ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP());
2124 } else {
2125 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {}",
2126 ci->client_id,
2127 ci->client_name,
2128 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0));
2129 }
2130 }
2131}
2132
2138std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
2139{
2140 auto socket = NetworkClientSocket::GetByClientID(client_id);
2141 return socket == nullptr ? "" : socket->GetPeerPublicKey();
2142}
2143
2144
2151{
2152 assert(c != nullptr);
2153
2154 if (!_network_server) return;
2155
2156 if (ci != nullptr) {
2157 /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
2158 ci->client_playas = c->index;
2160
2161 /*
2162 * This function is called from a command, but is only called for the server.
2163 * The client information is managed out-of-band from the commands, so to not have a
2164 * different state/president/company name in the different clients, we need to
2165 * circumvent the normal ::Post logic and go directly to sending the command.
2166 */
2169
2170 NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
2171 }
2172}
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:23
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:141
uint32_t last_frame
Last frame we have executed.
Definition tcp_game.h:487
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition tcp_game.h:515
ClientID client_id
Client identifier.
Definition tcp_game.h:486
CommandQueue incoming_queue
The command-queue awaiting handling.
Definition tcp_game.h:489
std::chrono::steady_clock::time_point last_packet
Time we received the last frame.
Definition tcp_game.h:490
void SetInfo(NetworkClientInfo *info)
Sets the client info for this socket handler.
Definition tcp_game.h:505
const char * ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
uint32_t last_frame_server
Last frame the server has executed.
Definition tcp_game.h:488
NetworkClientInfo * info
Client info related to this socket.
Definition tcp_game.h:144
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:74
std::unique_ptr< class NetworkEncryptionHandler > send_encryption_handler
The handler for encrypting sent packets.
Definition core.h:50
std::unique_ptr< class NetworkEncryptionHandler > receive_encryption_handler
The handler for decrypting received packets.
Definition core.h:49
virtual std::unique_ptr< Packet > ReceivePacket()
Receives a packet for the given client.
Definition tcp.cpp:119
SOCKET sock
The socket currently connected to.
Definition tcp.h:38
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:58
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition tcp.cpp:76
A sort-of mixin that adds 'at(pos)' and 'operator[](pos)' implementations for 'ConvertibleThroughBase...
Class for handling the server side of the game connection.
NetworkRecvStatus SendRConResult(uint16_t colour, const std::string &command)
Send the result of a console action.
NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet &p) override
Gives the client a new name: string New name of the client.
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 Receive_CLIENT_QUIT(Packet &p) override
The client is quitting the game.
static const char * GetName()
Get the name used by the listener.
const std::string & GetClientIP()
Get the IP address/hostname of the connected client.
NetworkRecvStatus SendWelcome()
Send the client a welcome message with some basic information.
NetworkRecvStatus SendAuthRequest()
Request the game password.
~ServerNetworkGameSocketHandler()
Clear everything related to this client.
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 SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64_t data)
Send a chat message.
NetworkRecvStatus SendGameInfo()
Send the client information about the server.
NetworkRecvStatus SendJoin(ClientID client_id)
Tell that a client joined.
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 SendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
Send a chat message from external source.
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 SendError(NetworkErrorCode error, const std::string &reason={})
Send an error to the client, and close its connection.
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 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.
ServerNetworkGameSocketHandler(SOCKET s)
Create a new socket for the server side of the game 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.
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.
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:45
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:58
static const uint NETWORK_CHAT_LENGTH
The maximum length of a chat message, in bytes including '\0'.
Definition config.h:61
static const uint NETWORK_REVISION_LENGTH
The maximum length of the revision, in bytes including '\0'.
Definition config.h:56
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition config.h:59
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:57
void IConsoleCmdExec(const std::string &command_string, const uint recurse_count)
Execute a given command passed to us.
Definition console.cpp:291
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:89
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:23
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition core.h:28
@ NETWORK_RECV_STATUS_SERVER_ERROR
The server told us we made an error.
Definition core.h:30
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition core.h:24
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition core.h:29
#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:19
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:20
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:18
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:294
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition gfx_type.h:357
uint32_t _last_sync_frame
Used in the server to store the last time a sync packet was sent to clients.
Definition network.cpp:79
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:71
uint32_t _frame_counter
The current frame.
Definition network.cpp:78
StringList _network_ban_list
The banned clients.
Definition network.cpp:75
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:68
bool _network_server
network-server is active
Definition network.cpp:66
uint32_t _sync_seed_1
Seed to compare during sync checks.
Definition network.cpp:81
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:89
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:77
void NetworkAdminClientUpdate(const NetworkClientInfo *ci)
Notify the admin network of a client update (if they did opt in for the respective update).
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data, bool from_admin)
Send chat to the admin network (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 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(const 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 NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64_t data=0, bool from_admin=false)
Send an actual chat message.
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.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
static IntervalTimer< TimerGameEconomy > _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);})
Quarterly "callback".
static IntervalTimer< TimerGameEconomy > _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);})
Daily "callback".
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
Change the client name of the given client.
void NetworkPrintClients()
Print all the clients to the console.
void NetworkServerUpdateGameInfo()
Update the server's NetworkServerGameInfo due to changes in settings.
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string)
Send an rcon reply to the client.
NetworkCompanyStatsArray NetworkGetCompanyStats()
Get the company stats.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler(_settings_client.network.rcon_authorized_keys)
Provides the authorized key validation for rcon.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
Ban, or kick, everyone joined from the given client's IP.
static IntervalTimer< TimerGameEconomy > _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY);})
Economy yearly "callback".
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password)
Provides the password validation for the game's password.
void NetworkServerSendConfigUpdate()
Send Config Update.
void NetworkServerKickClient(ClientID client_id, const std::string &reason)
Kick a single client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
static IntervalTimer< TimerGameEconomy > _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);})
Economy monthly "callback".
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.
static void NetworkCheckRestartMapYear()
Check if we want to restart the map based on the year.
static IntervalTimer< TimerGameCalendar > _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) { if(!_network_server) return;NetworkCheckRestartMapYear();})
Calendar yearly "callback".
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 void NetworkHandleCommandQueue(NetworkClientSocket *cs)
Handle the command-queue of a socket.
static IntervalTimer< TimerGameEconomy > _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);})
Economy weekly "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 NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
Send a chat message from external source.
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 void NetworkAutoCleanCompanies()
Remove companies that have not been used depending on the autoclean_companies setting and values for ...
void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const std::string &msg, ClientID from_id, int64_t data, bool from_admin)
Send an actual chat message.
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:325
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:64
@ SL_OK
completed successfully
Definition saveload.h:409
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:59
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
@ 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:277
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
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?
AbstractFileType abstract_ftype
Abstract type of file (scenario, heightmap, etc).
Definition saveload.h:418
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:24
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:116
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.
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.
~PacketWriter()
Make sure everything is cleaned up.
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:43
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition packet.cpp:364
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
Definition packet.cpp:347
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:318
std::string Recv_string(size_t length, StringValidationSettings settings=SVS_REPLACE_WITH_QUESTION_MARK)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
Definition packet.cpp:425
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
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.
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:24
@ ADMIN_FREQUENCY_MONTHLY
The admin gets information about this on a monthly basis.
Definition tcp_admin.h:100
@ ADMIN_FREQUENCY_QUARTERLY
The admin gets information about this on a quarterly basis.
Definition tcp_admin.h:101
@ ADMIN_FREQUENCY_ANUALLY
The admin gets information about this on a yearly basis.
Definition tcp_admin.h:102
@ ADMIN_FREQUENCY_WEEKLY
The admin gets information about this on a weekly basis.
Definition tcp_admin.h:99
@ ADMIN_FREQUENCY_DAILY
The admin gets information about this on a daily basis.
Definition tcp_admin.h:98
@ PACKET_SERVER_JOIN
Tells clients that a new client has joined.
Definition tcp_game.h:87
@ PACKET_SERVER_MAP_SIZE
Server tells the client what the (compressed) size of the map is.
Definition tcp_game.h:82
@ PACKET_SERVER_RCON
Response of the executed command on the server.
Definition tcp_game.h:111
@ PACKET_SERVER_MAP_BEGIN
Server tells the client that it is beginning to send the map.
Definition tcp_game.h:81
@ PACKET_SERVER_SYNC
Server tells the client what the random state should be.
Definition tcp_game.h:98
@ PACKET_SERVER_WAIT
Server tells the client there are some people waiting for the map as well.
Definition tcp_game.h:80
@ PACKET_SERVER_CONFIG_UPDATE
Some network configuration important to the client changed.
Definition tcp_game.h:119
@ PACKET_SERVER_ENABLE_ENCRYPTION
The server tells that authentication has completed and requests to enable encryption with the keys of...
Definition tcp_game.h:65
@ PACKET_SERVER_GAME_INFO
Information about the server.
Definition tcp_game.h:45
@ PACKET_SERVER_ERROR_QUIT
A server tells that a client has hit an error and did quit.
Definition tcp_game.h:125
@ PACKET_SERVER_CLIENT_INFO
Server sends you information about a client.
Definition tcp_game.h:76
@ PACKET_SERVER_WELCOME
Server welcomes you and gives you your ClientID.
Definition tcp_game.h:75
@ PACKET_SERVER_BANNED
The server has banned you.
Definition tcp_game.h:34
@ PACKET_SERVER_FRAME
Server tells the client what frame it is in, and thus to where the client may progress.
Definition tcp_game.h:96
@ PACKET_SERVER_EXTERNAL_CHAT
Server distributing the message from external source.
Definition tcp_game.h:107
@ PACKET_SERVER_CHAT
Server distributing the message of a client (or itself).
Definition tcp_game.h:106
@ PACKET_SERVER_COMMAND
Server distributes a command to (all) the clients.
Definition tcp_game.h:102
@ PACKET_SERVER_SHUTDOWN
The server is shutting down.
Definition tcp_game.h:50
@ PACKET_SERVER_AUTH_REQUEST
The server requests the client to authenticate using a number of methods.
Definition tcp_game.h:63
@ PACKET_SERVER_NEWGAME
The server is preparing to start a new game.
Definition tcp_game.h:49
@ PACKET_SERVER_MOVE
Server tells everyone that someone is moved to another company.
Definition tcp_game.h:115
@ PACKET_SERVER_MAP_DATA
Server sends bits of the map to the client.
Definition tcp_game.h:83
@ PACKET_SERVER_FULL
The server is full and has no place for you.
Definition tcp_game.h:33
@ PACKET_SERVER_QUIT
A server tells that a client has quit.
Definition tcp_game.h:123
@ PACKET_SERVER_ERROR
Server sending an error message to the client.
Definition tcp_game.h:38
@ PACKET_SERVER_CHECK_NEWGRFS
Server sends NewGRF IDs and MD5 checksums for the client to check.
Definition tcp_game.h:71
@ PACKET_SERVER_MAP_DONE
Server tells it has just sent the last bits of the map to the client.
Definition tcp_game.h:84
@ 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:3224
@ WC_CLIENT_LIST
Client list; Window numbers: