OpenTTD Source 20260421-master-gc2fbc6fdeb
network_server.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "../strings_func.h"
13#include "network_admin.h"
14#include "network_server.h"
15#include "network_udp.h"
16#include "network_base.h"
17#include "../console_func.h"
18#include "../company_base.h"
19#include "../command_func.h"
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"
31#include "../company_cmd.h"
32#include "../rev.h"
33#include "../timer/timer.h"
37#include <mutex>
38#include <condition_variable>
39
40#include "table/strings.h"
41
42#include "../safeguards.h"
43
44
45/* This file handles all the server-commands */
46
50
52static_assert(NetworkClientSocketPool::MAX_SIZE > MAX_CLIENTS);
53
57
58
60
64
65
69 std::unique_ptr<Packet> current;
70 size_t total_size;
71 std::deque<std::unique_ptr<Packet>> packets;
72 std::mutex mutex;
73 std::condition_variable exit_sig;
74
82
84 ~PacketWriter() override
85 {
86 std::unique_lock<std::mutex> lock(this->mutex);
87
88 while (this->cs != nullptr) this->exit_sig.wait(lock);
89
90 /* This must all wait until the Destroy function is called. */
91
92 this->packets.clear();
93 this->current = nullptr;
94 }
95
106 void Destroy()
107 {
108 std::unique_lock<std::mutex> lock(this->mutex);
109
110 this->cs = nullptr;
111
112 this->exit_sig.notify_all();
113 lock.unlock();
114
115 /* Make sure the saving is completely cancelled. Yes,
116 * we need to handle the save finish as well as the
117 * next connection might just be requesting a map. */
118 WaitTillSaved();
119 }
120
127 {
128 /* Unsafe check for the queue being empty or not. */
129 if (this->packets.empty()) return false;
130
131 std::lock_guard<std::mutex> lock(this->mutex);
132
133 while (!this->packets.empty()) {
134 bool last_packet = this->packets.front()->GetPacketType() == to_underlying(PacketGameType::ServerMapDone);
135 this->cs->SendPacket(std::move(this->packets.front()));
136 this->packets.pop_front();
137
138 if (last_packet) return true;
139 }
140
141 return false;
142 }
143
144 void Write(uint8_t *buf, size_t size) override
145 {
146 std::lock_guard<std::mutex> lock(this->mutex);
147
148 /* We want to abort the saving when the socket is closed. */
149 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
150
151 if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PacketGameType::ServerMapData, TCP_MTU);
152
153 std::span<const uint8_t> to_write(buf, size);
154 while (!to_write.empty()) {
155 to_write = this->current->Send_bytes(to_write);
156
157 if (!this->current->CanWriteToPacket(1)) {
158 this->packets.push_back(std::move(this->current));
159 if (!to_write.empty()) this->current = std::make_unique<Packet>(this->cs, PacketGameType::ServerMapData, TCP_MTU);
160 }
161 }
162
163 this->total_size += size;
164 }
165
166 void Finish() override
167 {
168 std::lock_guard<std::mutex> lock(this->mutex);
169
170 /* We want to abort the saving when the socket is closed. */
171 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
172
173 /* Make sure the last packet is flushed. */
174 if (this->current != nullptr) this->packets.push_back(std::move(this->current));
175
176 /* Add a packet stating that this is the end to the queue. */
177 this->packets.push_back(std::make_unique<Packet>(this->cs, PacketGameType::ServerMapDone));
178
179 /* Fast-track the size to the client. */
180 auto p = std::make_unique<Packet>(this->cs, PacketGameType::ServerMapSize);
181 p->Send_uint32((uint32_t)this->total_size);
182 this->packets.push_front(std::move(p));
183 }
184};
185
186
194{
196 this->receive_limit = _settings_client.network.bytes_per_frame_burst;
197
198 Debug(net, 9, "client[{}] status = INACTIVE", this->client_id);
199
200 /* The Socket and Info pools need to be the same in size. After all,
201 * each Socket will be associated with at most one Info object. As
202 * such if the Socket was allocated the Info object can as well. */
204}
205
210{
211 delete this->GetInfo();
212
215
216 if (this->savegame != nullptr) {
217 this->savegame->Destroy();
218 this->savegame = nullptr;
219 }
220
222}
223
225{
226 /* Only allow receiving when we have some buffer free; this value
227 * can go negative, but eventually it will become positive again. */
228 if (this->receive_limit <= 0) return nullptr;
229
230 /* We can receive a packet, so try that and if needed account for
231 * the amount of received data. */
232 std::unique_ptr<Packet> p = this->NetworkTCPSocketHandler::ReceivePacket();
233 if (p != nullptr) this->receive_limit -= p->Size();
234 return p;
235}
236
238{
240 /*
241 * Sending a message just before leaving the game calls cs->SendPackets.
242 * This might invoke this function, which means that when we close the
243 * connection after cs->SendPackets we will close an already closed
244 * connection. This handles that case gracefully without having to make
245 * that code any more complex or more aware of the validity of the socket.
246 */
247 if (this->IsPendingDeletion() || this->sock == INVALID_SOCKET) return status;
248
250 /* We did not receive a leave message from this client... */
251 std::string client_name = this->GetClientName();
252
253 NetworkTextMessage(NetworkAction::ClientLeave, CC_DEFAULT, false, client_name, "", STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
254
255 /* Inform other clients of this... strange leaving ;) */
257 if (new_cs->status >= STATUS_AUTHORIZED && this != new_cs) {
258 new_cs->SendErrorQuit(this->client_id, NetworkErrorCode::ConnectionLost);
259 }
260 }
261 }
262
263 /* If we were transferring a map to this client, stop the savegame creation
264 * process and queue the next client to receive the map. */
265 if (this->status == STATUS_MAP) {
266 /* Ensure the saving of the game is stopped too. */
267 this->savegame->Destroy();
268 this->savegame = nullptr;
269
270 this->CheckNextClientToSendMap(this);
271 }
272
274 Debug(net, 3, "[{}] Client #{} closed connection", ServerNetworkGameSocketHandler::GetName(), this->client_id);
275
276 /* We just lost one client :( */
277 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
278 extern uint8_t _network_clients_connected;
280
281 this->SendPackets(true);
282
283 this->DeferDeletion();
284
285 return status;
286}
287
293{
294 extern uint8_t _network_clients_connected;
296
297 /* We can't go over the MAX_CLIENTS limit here. However, the
298 * pool must have place for all clients and ourself. */
301 return accept;
302}
303
306{
308 if (cs->writable) {
309 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
310 /* This client is in the middle of a map-send, call the function for that */
311 cs->SendMap();
312 }
313 }
314 }
315}
316
318
319/***********
320 * Sending functions
321 ************/
322
329{
330 Debug(net, 9, "client[{}] SendClientInfo(): client_id={}", this->client_id, ci->client_id);
331
332 if (ci->client_id != INVALID_CLIENT_ID) {
333 auto p = std::make_unique<Packet>(this, PacketGameType::ServerClientInfo);
334 p->Send_uint32(ci->client_id);
335 p->Send_uint8 (ci->client_playas);
336 p->Send_string(ci->client_name);
337 p->Send_string(ci->public_key);
338
339 this->SendPacket(std::move(p));
340 }
342}
343
349{
350 Debug(net, 9, "client[{}] SendGameInfo()", this->client_id);
351
352 auto p = std::make_unique<Packet>(this, PacketGameType::ServerGameInfo, TCP_MTU);
354
355 this->SendPacket(std::move(p));
356
358}
359
367{
368 Debug(net, 9, "client[{}] SendError(): error={}", this->client_id, error);
369
370 auto p = std::make_unique<Packet>(this, PacketGameType::ServerError);
371
372 p->Send_uint8(to_underlying(error));
373 if (!reason.empty()) p->Send_string(reason);
374 this->SendPacket(std::move(p));
375
376 StringID strid = GetNetworkErrorMsg(error);
377
378 /* Only send when the current client was in game */
379 if (this->status >= STATUS_AUTHORIZED) {
380 std::string client_name = this->GetClientName();
381
382 Debug(net, 1, "'{}' made an error and has been disconnected: {}", client_name, GetString(strid));
383
384 if (error == NetworkErrorCode::Kicked && !reason.empty()) {
385 NetworkTextMessage(NetworkAction::ClientKicked, CC_DEFAULT, false, client_name, reason, strid);
386 } else {
387 NetworkTextMessage(NetworkAction::ClientLeave, CC_DEFAULT, false, client_name, "", strid);
388 }
389
391 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
392 /* Some errors we filter to a more general error. Clients don't have to know the real
393 * reason a joining failed. */
396 }
397 new_cs->SendErrorQuit(this->client_id, error);
398 }
399 }
400
402 } else {
403 Debug(net, 1, "Client {} made an error and has been disconnected: {}", this->client_id, GetString(strid));
404 }
405
406 /* The client made a mistake, so drop the connection now! */
408}
409
415{
416 Debug(net, 9, "client[{}] SendNewGRFCheck()", this->client_id);
417
418 /* Invalid packet when status is anything but STATUS_IDENTIFY. */
420
421 Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
423
424 if (_grfconfig.empty()) {
425 /* There are no NewGRFs, so they're welcome. */
426 return this->SendWelcome();
427 }
428
429 auto p = std::make_unique<Packet>(this, PacketGameType::ServerCheckNewGRFs, TCP_MTU);
430
431 uint grf_count = std::ranges::count_if(_grfconfig, [](const auto &c){ return !c->flags.Test(GRFConfigFlag::Static); });
432 p->Send_uint8 (grf_count);
433
434 for (const auto &c : _grfconfig) {
435 if (!c->flags.Test(GRFConfigFlag::Static)) SerializeGRFIdentifier(*p, c->ident);
436 }
437
438 this->SendPacket(std::move(p));
440}
441
447{
448 Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
449
450 /* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
452
453 Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
454 this->status = STATUS_AUTH_GAME;
455
456 /* Reset 'lag' counters */
458
459 if (this->authentication_handler == nullptr) {
461 }
462
463 auto p = std::make_unique<Packet>(this, PacketGameType::ServerAuthenticationRequest);
464 this->authentication_handler->SendRequest(*p);
465
466 this->SendPacket(std::move(p));
468}
469
475{
476 Debug(net, 9, "client[{}] SendEnableEncryption()", this->client_id);
477
478 /* Invalid packet when status is anything but STATUS_AUTH_GAME. */
480
481 auto p = std::make_unique<Packet>(this, PacketGameType::ServerEnableEncryption);
482 this->authentication_handler->SendEnableEncryption(*p);
483 this->SendPacket(std::move(p));
485}
486
492{
493 Debug(net, 9, "client[{}] SendWelcome()", this->client_id);
494
495 /* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
497
498 Debug(net, 9, "client[{}] status = AUTHORIZED", this->client_id);
500
501 /* Reset 'lag' counters */
503
504 _network_game_info.clients_on++;
505
506 auto p = std::make_unique<Packet>(this, PacketGameType::ServerWelcome);
507 p->Send_uint32(this->client_id);
508 this->SendPacket(std::move(p));
509
510 /* Transmit info about all the active clients */
512 if (new_cs != this && new_cs->status >= STATUS_AUTHORIZED) {
513 this->SendClientInfo(new_cs->GetInfo());
514 }
515 }
516 /* Also send the info of the server */
518}
519
525{
526 Debug(net, 9, "client[{}] SendWait()", this->client_id);
527
528 int waiting = 1; // current player getting the map counts as 1
529
530 /* Count how many clients are waiting in the queue, in front of you! */
532 if (new_cs->status != STATUS_MAP_WAIT) continue;
533 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++;
534 }
535
536 auto p = std::make_unique<Packet>(this, PacketGameType::ServerWaitForMap);
537 p->Send_uint8(waiting);
538 this->SendPacket(std::move(p));
540}
541
547{
548 Debug(net, 9, "client[{}] CheckNextClientToSendMap()", this->client_id);
549
550 /* Find the best candidate for joining, i.e. the first joiner. */
551 NetworkClientSocket *best = nullptr;
553 if (ignore_cs == new_cs) continue;
554
555 if (new_cs->status == STATUS_MAP_WAIT) {
556 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)) {
557 best = new_cs;
558 }
559 }
560 }
561
562 /* Is there someone else to join? */
563 if (best != nullptr) {
564 /* Let the first start joining. */
566 best->SendMap();
567
568 /* And update the rest. */
570 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
571 }
572 }
573}
574
580{
581 if (this->status < STATUS_AUTHORIZED) {
582 /* Illegal call, return error and ignore the packet */
584 }
585
586 if (this->status == STATUS_AUTHORIZED) {
587 Debug(net, 9, "client[{}] SendMap(): first_packet", this->client_id);
588
589 WaitTillSaved();
590 this->savegame = std::make_shared<PacketWriter>(this);
591
592 /* Now send the _frame_counter and how many packets are coming */
593 auto p = std::make_unique<Packet>(this, PacketGameType::ServerMapBegin);
594 p->Send_uint32(_frame_counter);
595 this->SendPacket(std::move(p));
596
598 Debug(net, 9, "client[{}] status = MAP", this->client_id);
599 this->status = STATUS_MAP;
600 /* Mark the start of download */
603
604 /* Make a dump of the current game */
605 if (SaveWithFilter(this->savegame, true) != SL_OK) UserError("network savedump failed");
606 }
607
608 if (this->status == STATUS_MAP) {
609 bool last_packet = this->savegame->TransferToNetworkQueue();
610 if (last_packet) {
611 Debug(net, 9, "client[{}] SendMap(): last_packet", this->client_id);
612
613 /* Done reading, make sure saving is done as well */
614 this->savegame->Destroy();
615 this->savegame = nullptr;
616
617 /* Set the status to DONE_MAP, no we will wait for the client
618 * to send it is ready (maybe that happens like never ;)) */
619 Debug(net, 9, "client[{}] status = DONE_MAP", this->client_id);
620 this->status = STATUS_DONE_MAP;
621
623 }
624 }
626}
627
634{
635 Debug(net, 9, "client[{}] SendJoin(): client_id={}", this->client_id, client_id);
636
637 auto p = std::make_unique<Packet>(this, PacketGameType::ServerClientJoined);
638
639 p->Send_uint32(client_id);
640
641 this->SendPacket(std::move(p));
643}
644
650{
651 auto p = std::make_unique<Packet>(this, PacketGameType::ServerFrame);
652 p->Send_uint32(_frame_counter);
653 p->Send_uint32(_frame_counter_max);
654#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
655 p->Send_uint32(_sync_seed_1);
656#ifdef NETWORK_SEND_DOUBLE_SEED
657 p->Send_uint32(_sync_seed_2);
658#endif
659#endif
660
661 /* If token equals 0, we need to make a new token and send that. */
662 if (this->last_token == 0) {
663 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
664 p->Send_uint8(this->last_token);
665 }
666
667 this->SendPacket(std::move(p));
669}
670
676{
677 Debug(net, 9, "client[{}] SendSync(), frame_counter={}, sync_seed_1={}", this->client_id, _frame_counter, _sync_seed_1);
678
679 auto p = std::make_unique<Packet>(this, PacketGameType::ServerSync);
680 p->Send_uint32(_frame_counter);
681 p->Send_uint32(_sync_seed_1);
682
683#ifdef NETWORK_SEND_DOUBLE_SEED
684 p->Send_uint32(_sync_seed_2);
685#endif
686 this->SendPacket(std::move(p));
688}
689
696{
697 Debug(net, 9, "client[{}] SendCommand(): cmd={}", this->client_id, cp.cmd);
698
699 auto p = std::make_unique<Packet>(this, PacketGameType::ServerCommand);
700
702 p->Send_uint32(cp.frame);
703 p->Send_bool (cp.my_cmd);
704
705 this->SendPacket(std::move(p));
707}
708
718NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, std::string_view msg, int64_t data)
719{
720 Debug(net, 9, "client[{}] SendChat(): action={}, client_id={}, self_send={}", this->client_id, action, client_id, self_send);
721
723
724 auto p = std::make_unique<Packet>(this, PacketGameType::ServerChat);
725
726 p->Send_uint8(to_underlying(action));
727 p->Send_uint32(client_id);
728 p->Send_bool (self_send);
729 p->Send_string(msg);
730 p->Send_uint64(data);
731
732 this->SendPacket(std::move(p));
734}
735
744NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
745{
746 Debug(net, 9, "client[{}] SendExternalChat(): source={}", this->client_id, source);
747
749
750 auto p = std::make_unique<Packet>(this, PacketGameType::ServerExternalChat);
751
752 p->Send_string(source);
753 p->Send_uint16(colour);
754 p->Send_string(user);
755 p->Send_string(msg);
756
757 this->SendPacket(std::move(p));
759}
760
768{
769 Debug(net, 9, "client[{}] SendErrorQuit(): client_id={}, errorno={}", this->client_id, client_id, errorno);
770
771 auto p = std::make_unique<Packet>(this, PacketGameType::ServerErrorQuit);
772
773 p->Send_uint32(client_id);
774 p->Send_uint8(to_underlying(errorno));
775
776 this->SendPacket(std::move(p));
778}
779
786{
787 Debug(net, 9, "client[{}] SendQuit(): client_id={}", this->client_id, client_id);
788
789 auto p = std::make_unique<Packet>(this, PacketGameType::ServerQuit);
790
791 p->Send_uint32(client_id);
792
793 this->SendPacket(std::move(p));
795}
796
802{
803 Debug(net, 9, "client[{}] SendShutdown()", this->client_id);
804
805 auto p = std::make_unique<Packet>(this, PacketGameType::ServerShutdown);
806 this->SendPacket(std::move(p));
808}
809
815{
816 Debug(net, 9, "client[{}] SendNewGame()", this->client_id);
817
818 auto p = std::make_unique<Packet>(this, PacketGameType::ServerNewGame);
819 this->SendPacket(std::move(p));
821}
822
830{
831 Debug(net, 9, "client[{}] SendRConResult()", this->client_id);
832
833 auto p = std::make_unique<Packet>(this, PacketGameType::ServerRemoteConsoleCommand);
834
835 p->Send_uint16(colour);
836 p->Send_string(command);
837 this->SendPacket(std::move(p));
839}
840
848{
849 Debug(net, 9, "client[{}] SendMove(): client_id={}", this->client_id, client_id);
850
851 auto p = std::make_unique<Packet>(this, PacketGameType::ServerMove);
852
853 p->Send_uint32(client_id);
854 p->Send_uint8(company_id);
855 this->SendPacket(std::move(p));
857}
858
864{
865 Debug(net, 9, "client[{}] SendConfigUpdate()", this->client_id);
866
867 auto p = std::make_unique<Packet>(this, PacketGameType::ServerConfigurationUpdate);
868
869 p->Send_uint8(_settings_client.network.max_companies);
870 p->Send_string(_settings_client.network.server_name);
871 this->SendPacket(std::move(p));
873}
874
875/***********
876 * Receiving functions
877 ************/
878
880{
881 Debug(net, 9, "client[{}] ReceiveClientGameInfo()", this->client_id);
882
883 return this->SendGameInfo();
884}
885
887{
888 if (this->status != STATUS_NEWGRFS_CHECK) {
889 /* Illegal call, return error and ignore the packet */
891 }
892
893 Debug(net, 9, "client[{}] ReceiveClientNewGRFsChecked()", this->client_id);
894
895 return this->SendWelcome();
896}
897
899{
900 if (this->status != STATUS_INACTIVE) {
901 /* Illegal call, return error and ignore the packet */
903 }
904
905 if (_network_game_info.clients_on >= _settings_client.network.max_clients) {
906 /* Turns out we are full. Inform the user about this. */
908 }
909
910 std::string client_revision = p.Recv_string(NETWORK_REVISION_LENGTH);
911 uint32_t newgrf_version = p.Recv_uint32();
912
913 Debug(net, 9, "client[{}] ReceiveClientJoin(): client_revision={}, newgrf_version={}", this->client_id, client_revision, newgrf_version);
914
915 /* Check if the client has revision control enabled */
916 if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
917 /* Different revisions!! */
919 }
920
921 return this->SendAuthRequest();
922}
923
925{
927
928 Debug(net, 9, "client[{}] ReceiveClientIdentify()", this->client_id);
929
930 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
931 CompanyID playas = (Owner)p.Recv_uint8();
932
934
935 /* join another company does not affect these values */
936 switch (playas.base()) {
937 case COMPANY_NEW_COMPANY.base(): // New company
938 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
940 }
941 break;
942 case COMPANY_SPECTATOR.base(): // Spectator
943 break;
944 default: // Join another company (companies 1..MAX_COMPANIES (index 0..(MAX_COMPANIES-1)))
945 if (!Company::IsValidHumanID(playas)) {
947 }
948
949 const Company *c = Company::Get(playas);
950 if (!c->allow_any && !c->allow_list.Contains(this->peer_public_key)) {
951 /* When we're not authorized, just bump us to a spectator. */
952 playas = COMPANY_SPECTATOR;
953 }
954 break;
955 }
956
957 if (!NetworkIsValidClientName(client_name)) {
958 /* An invalid client name was given. However, the client ensures the name
959 * is valid before it is sent over the network, so something went horribly
960 * wrong. This is probably someone trying to troll us. */
962 }
963
964 if (!NetworkMakeClientNameUnique(client_name)) { // Change name if duplicate
965 /* We could not create a name for this client */
967 }
968
971 this->SetInfo(ci);
973 ci->client_name = std::move(client_name);
974 ci->client_playas = playas;
975 ci->public_key = this->peer_public_key;
976 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, ci->index);
977
978 /* Make sure companies to which people try to join are not autocleaned */
979 Company *c = Company::GetIfValid(playas);
980 if (c != nullptr) c->months_empty = 0;
981
982 return this->SendNewGRFCheck();
983}
984
1002
1004{
1005 if (this->status != STATUS_AUTH_GAME) {
1007 }
1008
1009 Debug(net, 9, "client[{}] ReceiveClientAuthenticationResponse()", this->client_id);
1010
1011 auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
1012 switch (this->authentication_handler->ReceiveResponse(p)) {
1014 break;
1015
1017 return this->SendAuthRequest();
1018
1020 default:
1021 return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
1022 }
1023
1025 if (status != NETWORK_RECV_STATUS_OKAY) return status;
1026
1027 this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
1028 this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
1029 this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
1030 this->authentication_handler = nullptr;
1031
1032 Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
1033 this->status = STATUS_IDENTIFY;
1034
1035 /* Reset 'lag' counters */
1037
1039}
1040
1042{
1043 /* The client was never joined.. so this is impossible, right?
1044 * Ignore the packet, give the client a warning, and close the connection */
1047 }
1048
1049 Debug(net, 9, "client[{}] ReceiveClientGetMap()", this->client_id);
1050
1051 /* Check if someone else is receiving the map */
1053 if (new_cs->status == STATUS_MAP) {
1054 /* Tell the new client to wait */
1055 Debug(net, 9, "client[{}] status = MAP_WAIT", this->client_id);
1056 this->status = STATUS_MAP_WAIT;
1057 return this->SendWait();
1058 }
1059 }
1060
1061 /* We receive a request to upload the map.. give it to the client! */
1062 return this->SendMap();
1063}
1064
1066{
1067 /* Client has the map, now start syncing */
1068 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
1069 Debug(net, 9, "client[{}] ReceiveClientMapOk()", this->client_id);
1070
1071 std::string client_name = this->GetClientName();
1072
1073 NetworkTextMessage(NetworkAction::ClientJoin, CC_DEFAULT, false, client_name, "", this->client_id);
1075
1076 Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name);
1077
1078 /* Mark the client as pre-active, and wait for an ACK
1079 * so we know it is done loading and in sync with us */
1080 Debug(net, 9, "client[{}] status = PRE_ACTIVE", this->client_id);
1081 this->status = STATUS_PRE_ACTIVE;
1083 this->SendFrame();
1084 this->SendSync();
1085
1086 /* This is the frame the client receives
1087 * we need it later on to make sure the client is not too slow */
1088 this->last_frame = _frame_counter;
1090
1092 if (new_cs->status >= STATUS_AUTHORIZED) {
1093 new_cs->SendClientInfo(this->GetInfo());
1094 new_cs->SendJoin(this->client_id);
1095 }
1096 }
1097
1098 NetworkAdminClientInfo(this, true);
1099
1100 /* also update the new client with our max values */
1101 return this->SendConfigUpdate();
1102 }
1103
1104 /* Wrong status for this packet, give a warning to client, and close connection */
1106}
1107
1109{
1110 /* The client was never joined.. so this is impossible, right?
1111 * Ignore the packet, give the client a warning, and close the connection */
1114 }
1115
1116 if (this->incoming_queue.size() >= _settings_client.network.max_commands_in_queue) {
1118 }
1119
1120 Debug(net, 9, "client[{}] ReceiveClientCommand()", this->client_id);
1121
1122 CommandPacket cp;
1123 auto err = this->ReceiveCommand(p, cp);
1124
1126
1127 NetworkClientInfo *ci = this->GetInfo();
1128
1129 if (err.has_value()) {
1130 IConsolePrint(CC_WARNING, "Dropping client #{} (IP: {}) due to {}.", ci->client_id, this->GetClientIP(), *err);
1132 }
1133
1135 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a server only command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1136 return this->SendError(NetworkErrorCode::Kicked);
1137 }
1138
1140 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a non-spectator command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1141 return this->SendError(NetworkErrorCode::Kicked);
1142 }
1143
1151 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
1152 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1154 }
1155
1156 if (cp.cmd == Commands::CompanyControl) {
1157 if (cca != CompanyCtrlAction::New || cp.company != COMPANY_SPECTATOR) {
1159 }
1160
1161 /* Check if we are full - else it's possible for spectators to send a Commands::CompanyControl and the company is created regardless of max_companies! */
1162 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
1165 }
1166 }
1167
1169 /* Maybe the client just got moved before allowing? */
1171
1172 /* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
1173 std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<Commands::CompanyAllowListControl>::Args>(cp.data));
1174 if (!public_key.empty()) {
1175 bool found = false;
1177 if (info->public_key == public_key) {
1178 found = true;
1179 break;
1180 }
1181 }
1182
1183 /* Maybe the client just left? */
1184 if (!found) return NETWORK_RECV_STATUS_OKAY;
1185 }
1186 }
1187
1188 if (GetCommandFlags(cp.cmd).Test(CommandFlag::ClientID)) NetworkReplaceCommandClientId(cp, this->client_id);
1189
1190 this->incoming_queue.push_back(std::move(cp));
1192}
1193
1195{
1196 /* This packets means a client noticed an error and is reporting this
1197 * to us. Display the error and report it to the other clients */
1198 NetworkErrorCode errorno = static_cast<NetworkErrorCode>(p.Recv_uint8());
1199
1200 Debug(net, 9, "client[{}] ReceiveClientError(): errorno={}", this->client_id, errorno);
1201
1202 /* The client was never joined.. thank the client for the packet, but ignore it */
1205 }
1206
1207 std::string client_name = this->GetClientName();
1208 StringID strid = GetNetworkErrorMsg(errorno);
1209
1210 Debug(net, 1, "'{}' reported an error and is closing its connection: {}", client_name, GetString(strid));
1211
1212 NetworkTextMessage(NetworkAction::ClientLeave, CC_DEFAULT, false, client_name, "", strid);
1213
1215 if (new_cs->status >= STATUS_AUTHORIZED) {
1216 new_cs->SendErrorQuit(this->client_id, errorno);
1217 }
1218 }
1219
1220 NetworkAdminClientError(this->client_id, errorno);
1221
1223}
1224
1226{
1227 /* The client was never joined.. thank the client for the packet, but ignore it */
1230 }
1231
1232 Debug(net, 9, "client[{}] ReceiveClientQuit()", this->client_id);
1233
1234 /* The client wants to leave. Display this and report it to the other clients. */
1235 std::string client_name = this->GetClientName();
1236 NetworkTextMessage(NetworkAction::ClientLeave, CC_DEFAULT, false, client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1237
1239 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
1240 new_cs->SendQuit(this->client_id);
1241 }
1242 }
1243
1245
1247}
1248
1250{
1251 if (this->status < STATUS_AUTHORIZED) {
1252 /* Illegal call, return error and ignore the packet */
1254 }
1255
1256 uint32_t frame = p.Recv_uint32();
1257
1258 Debug(net, 9, "client[{}] ReceiveClientAck(): frame={}", this->client_id, frame);
1259
1260 /* The client is trying to catch up with the server */
1261 if (this->status == STATUS_PRE_ACTIVE) {
1262 /* The client is not yet caught up? */
1264
1265 /* Now it is! Unpause the game */
1266 Debug(net, 9, "client[{}] status = ACTIVE", this->client_id);
1267 this->status = STATUS_ACTIVE;
1269
1270 /* Execute script for, e.g. MOTD */
1271 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
1272 }
1273
1274 /* Get, and validate the token. */
1275 uint8_t token = p.Recv_uint8();
1276 if (token == this->last_token) {
1277 /* We differentiate between last_token_frame and last_frame so the lag
1278 * test uses the actual lag of the client instead of the lag for getting
1279 * the token back and forth; after all, the token is only sent every
1280 * time we receive a PacketGameType::ClientAck, after which we will send a new
1281 * token to the client. If the lag would be one day, then we would not
1282 * be sending the new token soon enough for the new daily scheduled
1283 * PacketGameType::ClientAck. This would then register the lag of the client as
1284 * two days, even when it's only a single day. */
1286 /* Request a new token. */
1287 this->last_token = 0;
1288 }
1289
1290 /* The client received the frame, make note of it */
1291 this->last_frame = frame;
1292 /* With those 2 values we can calculate the lag realtime */
1295}
1296
1297
1308void NetworkServerSendChat(NetworkAction action, NetworkChatDestinationType desttype, int dest, std::string_view msg, ClientID from_id, int64_t data, bool from_admin)
1309{
1310 const NetworkClientInfo *ci, *ci_own, *ci_to;
1311
1312 switch (desttype) {
1314 /* Are we sending to the server? */
1315 if ((ClientID)dest == CLIENT_ID_SERVER) {
1317 /* Display the text locally, and that is it */
1318 if (ci != nullptr) {
1319 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1320
1321 if (_settings_client.network.server_admin_chat) {
1322 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1323 }
1324 }
1325 } else {
1326 /* Else find the client to send the message to */
1327 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1328 if (cs->client_id == (ClientID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1329 cs->SendChat(action, from_id, false, msg, data);
1330 break;
1331 }
1332 }
1333 }
1334
1335 /* Display the message locally (so you know you have sent it) */
1336 if (from_id != (ClientID)dest) {
1337 if (from_id == CLIENT_ID_SERVER) {
1340 if (ci != nullptr && ci_to != nullptr) {
1341 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
1342 }
1343 } else {
1344 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1345 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1346 cs->SendChat(action, (ClientID)dest, true, msg, data);
1347 break;
1348 }
1349 }
1350 }
1351 }
1352 break;
1354 /* If this is false, the message is already displayed on the client who sent it. */
1355 bool show_local = true;
1356 /* Find all clients that belong to this company */
1357 ci_to = nullptr;
1358 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1359 ci = cs->GetInfo();
1360 if (ci != nullptr && ci->client_playas == (CompanyID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1361 cs->SendChat(action, from_id, false, msg, data);
1362 if (cs->client_id == from_id) show_local = false;
1363 ci_to = ci; // Remember a client that is in the company for company-name
1364 }
1365 }
1366
1367 /* if the server can read it, let the admin network read it, too. */
1368 if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) {
1369 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1370 }
1371
1374 if (ci != nullptr && ci_own != nullptr && ci_own->client_playas == dest) {
1375 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1376 if (from_id == CLIENT_ID_SERVER) show_local = false;
1377 ci_to = ci_own;
1378 }
1379
1380 /* There is no such client */
1381 if (ci_to == nullptr) break;
1382
1383 /* Display the message locally (so you know you have sent it) */
1384 if (ci != nullptr && show_local) {
1385 if (from_id == CLIENT_ID_SERVER) {
1386 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1387 std::string name = GetString(str, ci_to->client_playas);
1388 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
1389 } else {
1390 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1391 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1392 cs->SendChat(action, ci_to->client_id, true, msg, data);
1393 }
1394 }
1395 }
1396 }
1397 break;
1398 }
1399 default:
1400 Debug(net, 1, "Received unknown chat destination type {}; doing broadcast instead", desttype);
1401 [[fallthrough]];
1402
1404 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1405 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendChat(action, from_id, false, msg, data);
1406 }
1407
1408 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1409
1411 if (ci != nullptr) {
1412 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1413 }
1414 break;
1415 }
1416}
1417
1425void NetworkServerSendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
1426{
1427 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1428 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendExternalChat(source, colour, user, msg);
1429 }
1430 NetworkTextMessage(NetworkAction::ChatExternal, colour, false, user, msg, source);
1431}
1432
1434{
1435 if (this->status < STATUS_PRE_ACTIVE) {
1436 /* Illegal call, return error and ignore the packet */
1438 }
1439
1440 NetworkAction action = static_cast<NetworkAction>(p.Recv_uint8());
1442 int dest = p.Recv_uint32();
1443
1444 Debug(net, 9, "client[{}] ReceiveClientChat(): action={}, desttype={}, dest={}", this->client_id, action, desttype, dest);
1445
1446 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1447 int64_t data = p.Recv_uint64();
1448
1449 NetworkClientInfo *ci = this->GetInfo();
1450 switch (action) {
1454 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
1455 break;
1456 default:
1457 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to unknown chact action.", ci->client_id, this->GetClientIP());
1459 }
1461}
1462
1464{
1465 if (this->status != STATUS_ACTIVE) {
1466 /* Illegal call, return error and ignore the packet */
1468 }
1469
1470 Debug(net, 9, "client[{}] ReceiveClientSetName()", this->client_id);
1471
1473
1474 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
1475 ci = this->GetInfo();
1476
1478
1479 if (ci != nullptr) {
1480 if (!NetworkIsValidClientName(client_name)) {
1481 /* An invalid client name was given. However, the client ensures the name
1482 * is valid before it is sent over the network, so something went horribly
1483 * wrong. This is probably someone trying to troll us. */
1485 }
1486
1487 /* Display change */
1488 if (NetworkMakeClientNameUnique(client_name)) {
1490 ci->client_name = std::move(client_name);
1493 }
1494 }
1496}
1497
1499{
1500 if (this->status != STATUS_ACTIVE) return this->SendError(NetworkErrorCode::NotExpected);
1501
1502 Debug(net, 9, "client[{}] ReceiveClientRemoteConsoleCommand()", this->client_id);
1503
1504 std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
1505 std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1506
1507 if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
1508 /* We are allowed, nothing more to validate. */
1509 } else if (_settings_client.network.rcon_password.empty()) {
1511 } else if (_settings_client.network.rcon_password != password) {
1512 Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id);
1514 }
1515
1516 Debug(net, 3, "[rcon] Client-id {} executed: {}", this->client_id, command);
1517
1519 IConsoleCmdExec(command);
1522}
1523
1525{
1526 if (this->status != STATUS_ACTIVE) return this->SendError(NetworkErrorCode::NotExpected);
1527
1528 CompanyID company_id = (Owner)p.Recv_uint8();
1529
1530 Debug(net, 9, "client[{}] ReceiveClientMove(): company_id={}", this->client_id, company_id);
1531
1532 /* Check if the company is valid, we don't allow moving to AI companies */
1533 if (company_id != COMPANY_SPECTATOR) {
1534 if (!Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
1535
1536 const Company *c = Company::Get(company_id);
1537 if (!c->allow_any && !c->allow_list.Contains(this->peer_public_key)) {
1538 Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
1540 }
1541 }
1542
1543 /* if we get here we can move the client */
1544 NetworkServerDoMove(this->client_id, company_id);
1546}
1547
1553{
1554 NetworkCompanyStatsArray stats = {};
1555
1556 /* Go through all vehicles and count the type of vehicles */
1557 for (const Vehicle *v : Vehicle::Iterate()) {
1558 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1559 NetworkVehicleType type;
1560 switch (v->type) {
1561 case VEH_TRAIN: type = NetworkVehicleType::Train; break;
1563 case VEH_AIRCRAFT: type = NetworkVehicleType::Aircraft; break;
1564 case VEH_SHIP: type = NetworkVehicleType::Ship; break;
1565 default: continue;
1566 }
1567 stats[v->owner].num_vehicle[type]++;
1568 }
1569
1570 /* Go through all stations and count the types of stations */
1571 for (const Station *s : Station::Iterate()) {
1572 if (Company::IsValidID(s->owner)) {
1573 NetworkCompanyStats *npi = &stats[s->owner];
1574
1575 if (s->facilities.Test(StationFacility::Train)) npi->num_station[NetworkVehicleType::Train]++;
1576 if (s->facilities.Test(StationFacility::TruckStop)) npi->num_station[NetworkVehicleType::Truck]++;
1577 if (s->facilities.Test(StationFacility::BusStop)) npi->num_station[NetworkVehicleType::Bus]++;
1578 if (s->facilities.Test(StationFacility::Airport)) npi->num_station[NetworkVehicleType::Aircraft]++;
1579 if (s->facilities.Test(StationFacility::Dock)) npi->num_station[NetworkVehicleType::Ship]++;
1580 }
1581 }
1582
1583 return stats;
1584}
1585
1591{
1593
1594 if (ci == nullptr) return;
1595
1596 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, ci->client_playas, client_id);
1597
1598 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1600 cs->SendClientInfo(ci);
1601 }
1602 }
1603
1605}
1606
1613{
1614 CompanyMask has_clients{};
1615 CompanyMask has_vehicles{};
1616
1617 if (!_settings_client.network.autoclean_companies) return;
1618
1619 /* Detect the active companies */
1620 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1621 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1622 }
1623
1624 if (!_network_dedicated) {
1626 assert(ci != nullptr);
1627 if (Company::IsValidID(ci->client_playas)) has_clients.Set(ci->client_playas);
1628 }
1629
1630 if (_settings_client.network.autoclean_novehicles != 0) {
1631 for (const Company *c : Company::Iterate()) {
1632 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);
1633 }
1634 }
1635
1636 /* Go through all the companies */
1637 for (Company *c : Company::Iterate()) {
1638 /* Skip the non-active once */
1639 if (c->is_ai) continue;
1640
1641 if (!has_clients.Test(c->index)) {
1642 /* The company is empty for one month more */
1643 if (c->months_empty != std::numeric_limits<decltype(c->months_empty)>::max()) c->months_empty++;
1644
1645 /* Is the company empty for autoclean_protected-months? */
1646 if (_settings_client.network.autoclean_protected != 0 && c->months_empty > _settings_client.network.autoclean_protected) {
1647 /* Shut the company down */
1648 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, c->index, CompanyRemoveReason::Autoclean, INVALID_CLIENT_ID);
1649 IConsolePrint(CC_INFO, "Auto-cleaned company #{}.", c->index + 1);
1650 }
1651 /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
1652 if (_settings_client.network.autoclean_novehicles != 0 && c->months_empty > _settings_client.network.autoclean_novehicles && !has_vehicles.Test(c->index)) {
1653 /* Shut the company down */
1654 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, c->index, CompanyRemoveReason::Autoclean, INVALID_CLIENT_ID);
1655 IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
1656 }
1657 } else {
1658 /* It is not empty, reset the date */
1659 c->months_empty = 0;
1660 }
1661 }
1662}
1663
1669bool NetworkMakeClientNameUnique(std::string &name)
1670{
1671 bool is_name_unique = false;
1672 std::string original_name = name;
1673
1674 for (uint number = 1; !is_name_unique && number <= MAX_CLIENTS; number++) { // Something's really wrong when there're more names than clients
1675 is_name_unique = true;
1676 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1677 if (ci->client_name == name) {
1678 /* Name already in use */
1679 is_name_unique = false;
1680 break;
1681 }
1682 }
1683 /* Check if it is the same as the server-name */
1685 if (ci != nullptr) {
1686 if (ci->client_name == name) is_name_unique = false; // name already in use
1687 }
1688
1689 if (!is_name_unique) {
1690 /* Try a new name (<name> #1, <name> #2, and so on) */
1691 name = fmt::format("{} #{}", original_name, number);
1692
1693 /* The constructed client name is larger than the limit,
1694 * so... bail out as no valid name can be created. */
1695 if (name.size() >= NETWORK_CLIENT_NAME_LENGTH) return false;
1696 }
1697 }
1698
1699 return is_name_unique;
1700}
1701
1708bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
1709{
1710 /* Check if the name's already in use */
1712 if (ci->client_name == new_name) return false;
1713 }
1714
1716 if (ci == nullptr) return false;
1717
1719
1720 ci->client_name = new_name;
1721
1722 NetworkUpdateClientInfo(client_id);
1723 return true;
1724}
1725
1731{
1732 for (auto &cp : cs->outgoing_queue) cs->SendCommand(cp);
1733 cs->outgoing_queue.clear();
1734}
1735
1740void NetworkServer_Tick(bool send_frame)
1741{
1742#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1743 bool send_sync = false;
1744#endif
1745
1746#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1747 if (_frame_counter >= _last_sync_frame + _settings_client.network.sync_freq) {
1749 send_sync = true;
1750 }
1751#endif
1752
1753 /* Now we are done with the frame, inform the clients that they can
1754 * do their frame! */
1755 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1756 /* We allow a number of bytes per frame, but only to the burst amount
1757 * to be available for packet receiving at any particular time. */
1758 cs->receive_limit = std::min<size_t>(cs->receive_limit + _settings_client.network.bytes_per_frame,
1759 _settings_client.network.bytes_per_frame_burst);
1760
1761 /* Check if the speed of the client is what we can expect from a client */
1762 uint lag = NetworkCalculateLag(cs);
1763 switch (cs->status) {
1764 case NetworkClientSocket::STATUS_ACTIVE:
1765 if (lag > _settings_client.network.max_lag_time) {
1766 /* Client did still not report in within the specified limit. */
1767
1768 if (cs->last_packet + std::chrono::milliseconds(lag * MILLISECONDS_PER_TICK) > std::chrono::steady_clock::now()) {
1769 /* A packet was received in the last three game days, so the client is likely lagging behind. */
1770 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client's game state is more than {} ticks behind.", cs->client_id, cs->GetClientIP(), lag);
1771 } else {
1772 /* No packet was received in the last three game days; sounds like a lost connection. */
1773 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client did not respond for more than {} ticks.", cs->client_id, cs->GetClientIP(), lag);
1774 }
1775 cs->SendError(NetworkErrorCode::TimeoutComputer);
1776 continue;
1777 }
1778
1779 /* Report once per time we detect the lag, and only when we
1780 * received a packet in the last 2 seconds. If we
1781 * did not receive a packet, then the client is not just
1782 * slow, but the connection is likely severed. Mentioning
1783 * frame_freq is not useful in this case. */
1784 if (lag > (uint)Ticks::DAY_TICKS && cs->lag_test == 0 && cs->last_packet + std::chrono::seconds(2) > std::chrono::steady_clock::now()) {
1785 IConsolePrint(CC_WARNING, "[{}] Client #{} is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
1786 cs->lag_test = 1;
1787 }
1788
1789 if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) {
1790 /* This is a bad client! It didn't send the right token back within time. */
1791 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it fails to send valid acks.", cs->client_id, cs->GetClientIP());
1792 cs->SendError(NetworkErrorCode::TimeoutComputer);
1793 continue;
1794 }
1795 break;
1796
1797 case NetworkClientSocket::STATUS_INACTIVE:
1798 case NetworkClientSocket::STATUS_IDENTIFY:
1799 case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
1800 case NetworkClientSocket::STATUS_AUTHORIZED:
1801 /* NewGRF check and authorized states should be handled almost instantly.
1802 * So give them some lee-way, likewise for the query with inactive. */
1803 if (lag > _settings_client.network.max_init_time) {
1804 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);
1805 cs->SendError(NetworkErrorCode::TimeoutComputer);
1806 continue;
1807 }
1808 break;
1809
1810 case NetworkClientSocket::STATUS_MAP_WAIT:
1811 /* Send every two seconds a packet to the client, to make sure
1812 * it knows the server is still there; just someone else is
1813 * still receiving the map. */
1814 if (std::chrono::steady_clock::now() > cs->last_packet + std::chrono::seconds(2)) {
1815 cs->SendWait();
1816 /* We need to reset the timer, as otherwise we will be
1817 * spamming the client. Strictly speaking this variable
1818 * tracks when we last received a packet from the client,
1819 * but as it is waiting, it will not send us any till we
1820 * start sending them data. */
1821 cs->last_packet = std::chrono::steady_clock::now();
1822 }
1823 break;
1824
1825 case NetworkClientSocket::STATUS_MAP:
1826 /* Downloading the map... this is the amount of time since starting the saving. */
1827 if (lag > _settings_client.network.max_download_time) {
1828 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);
1829 cs->SendError(NetworkErrorCode::TimeoutMap);
1830 continue;
1831 }
1832 break;
1833
1834 case NetworkClientSocket::STATUS_DONE_MAP:
1835 case NetworkClientSocket::STATUS_PRE_ACTIVE:
1836 /* The map has been sent, so this is for loading the map and syncing up. */
1837 if (lag > _settings_client.network.max_join_time) {
1838 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);
1839 cs->SendError(NetworkErrorCode::TimeoutJoin);
1840 continue;
1841 }
1842 break;
1843
1844 case NetworkClientSocket::STATUS_AUTH_GAME:
1845 /* These don't block? */
1846 if (lag > _settings_client.network.max_password_time) {
1847 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);
1848 cs->SendError(NetworkErrorCode::TimeoutPassword);
1849 continue;
1850 }
1851 break;
1852
1853 case NetworkClientSocket::STATUS_END:
1854 /* Bad server/code. */
1855 NOT_REACHED();
1856 }
1857
1858 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
1859 /* Check if we can send command, and if we have anything in the queue */
1861
1862 /* Send an updated _frame_counter_max to the client */
1863 if (send_frame) cs->SendFrame();
1864
1865#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1866 /* Send a sync-check packet */
1867 if (send_sync) cs->SendSync();
1868#endif
1869 }
1870 }
1871}
1872
1875{
1876 _settings_newgame.game_creation.generation_seed = GENERATE_NEW_SEED;
1877 switch (_file_to_saveload.ftype.abstract) {
1881 break;
1882
1885 break;
1886
1887 default:
1889 }
1890}
1891
1894{
1895 if (!_network_server) return;
1896
1897 /* If setting is 0, this feature is disabled. */
1898 if (_settings_client.network.restart_hours == 0) return;
1899
1900 Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);
1902});
1903
1909{
1910 if (!_network_server) return;
1911
1912 _network_restart_map_timer.SetInterval({ std::chrono::hours(_settings_client.network.restart_hours), TimerGameRealtime::Trigger::Unpaused }, reset);
1913}
1914
1917{
1918 /* If setting is 0, this feature is disabled. */
1919 if (_settings_client.network.restart_game_year == 0) return;
1920
1921 if (TimerGameCalendar::year >= _settings_client.network.restart_game_year) {
1922 Debug(net, 3, "Auto-restarting map: year {} reached", TimerGameCalendar::year);
1924 }
1925}
1926
1928static const IntervalTimer<TimerGameCalendar> _calendar_network_yearly({ TimerGameCalendar::Trigger::Year, TimerGameCalendar::Priority::None }, [](auto) {
1929 if (!_network_server) return;
1930
1932});
1933
1935static const IntervalTimer<TimerGameEconomy> _economy_network_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::None}, [](auto)
1936{
1937 if (!_network_server) return;
1938
1940});
1941
1943static const IntervalTimer<TimerGameEconomy> _network_quarterly({TimerGameEconomy::Trigger::Quarter, TimerGameEconomy::Priority::None}, [](auto)
1944{
1945 if (!_network_server) return;
1946
1949});
1950
1952static const IntervalTimer<TimerGameEconomy> _network_monthly({TimerGameEconomy::Trigger::Month, TimerGameEconomy::Priority::None}, [](auto)
1953{
1954 if (!_network_server) return;
1955
1958});
1959
1961static const IntervalTimer<TimerGameEconomy> _network_weekly({TimerGameEconomy::Trigger::Week, TimerGameEconomy::Priority::None}, [](auto)
1962{
1963 if (!_network_server) return;
1964
1966});
1967
1969static const IntervalTimer<TimerGameEconomy> _economy_network_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::None}, [](auto)
1970{
1971 if (!_network_server) return;
1972
1974});
1975
1981{
1982 return this->client_address.GetHostname();
1983}
1984
1987{
1988 static const std::string_view stat_str[] = {
1989 "inactive",
1990 "authorizing",
1991 "identifying client",
1992 "checking NewGRFs",
1993 "authorized",
1994 "waiting",
1995 "loading map",
1996 "map done",
1997 "ready",
1998 "active"
1999 };
2000 static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
2001
2002 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2003 NetworkClientInfo *ci = cs->GetInfo();
2004 if (ci == nullptr) continue;
2005 uint lag = NetworkCalculateLag(cs);
2006
2007 std::string_view status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
2008 IConsolePrint(CC_INFO, "Client #{} name: '{}' status: '{}' frame-lag: {} company: {} IP: {}",
2009 cs->client_id, ci->client_name, status, lag,
2010 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2011 cs->GetClientIP());
2012 }
2013}
2014
2019{
2020 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2021 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
2022 }
2023}
2024
2030
2036void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
2037{
2038 /* Only allow non-dedicated servers and normal clients to be moved */
2039 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
2040
2042 assert(ci != nullptr);
2043
2044 /* No need to waste network resources if the client is in the company already! */
2045 if (ci->client_playas == company_id) return;
2046
2047 ci->client_playas = company_id;
2048
2049 if (client_id == CLIENT_ID_SERVER) {
2050 SetLocalCompany(company_id);
2051 } else {
2052 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
2053 /* When the company isn't authorized we can't move them yet. */
2054 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
2055 cs->SendMove(client_id, company_id);
2056 }
2057
2058 /* Announce the client's move. */
2059 NetworkUpdateClientInfo(client_id);
2060
2061 if (company_id == COMPANY_SPECTATOR) {
2062 /* The client has joined spectators. */
2064 } else {
2065 /* The client has joined another company. */
2066 std::string company_name = GetString(STR_COMPANY_NAME, company_id);
2068 }
2069
2071}
2072
2079void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, std::string_view string)
2080{
2081 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
2082}
2083
2089void NetworkServerKickClient(ClientID client_id, std::string_view reason)
2090{
2091 if (client_id == CLIENT_ID_SERVER) return;
2092 NetworkClientSocket::GetByClientID(client_id)->SendError(NetworkErrorCode::Kicked, reason);
2093}
2094
2102uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
2103{
2104 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban, reason);
2105}
2106
2114uint NetworkServerKickOrBanIP(std::string_view ip, bool ban, std::string_view reason)
2115{
2116 /* Add address to ban-list */
2117 if (ban) {
2118 bool contains = false;
2119 for (const auto &iter : _network_ban_list) {
2120 if (iter == ip) {
2121 contains = true;
2122 break;
2123 }
2124 }
2125 if (!contains) _network_ban_list.emplace_back(ip);
2126 }
2127
2128 uint n = 0;
2129
2130 /* There can be multiple clients with the same IP, kick them all but don't kill the server,
2131 * or the client doing the rcon. The latter can't be kicked because kicking frees closes
2132 * and subsequently free the connection related instances, which we would be reading from
2133 * and writing to after returning. So we would read or write data from freed memory up till
2134 * the segfault triggers. */
2135 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2136 if (cs->client_id == CLIENT_ID_SERVER) continue;
2137 if (cs->client_id == _redirect_console_to_client) continue;
2138 if (cs->client_address.IsInNetmask(ip)) {
2139 NetworkServerKickClient(cs->client_id, reason);
2140 n++;
2141 }
2142 }
2143
2144 return n;
2145}
2146
2152bool NetworkCompanyHasClients(CompanyID company)
2153{
2154 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
2155 if (ci->client_playas == company) return true;
2156 }
2157 return false;
2158}
2159
2160
2166{
2167 const NetworkClientInfo *ci = this->GetInfo();
2168 if (ci != nullptr && !ci->client_name.empty()) return ci->client_name;
2169
2170 return fmt::format("Client #{}", this->client_id);
2171}
2172
2177{
2179 if (_network_server) {
2180 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {} IP: {}",
2181 ci->client_id,
2182 ci->client_name,
2183 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2184 ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP());
2185 } else {
2186 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {}",
2187 ci->client_id,
2188 ci->client_name,
2189 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0));
2190 }
2191 }
2192}
2193
2199std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
2200{
2201 auto socket = NetworkClientSocket::GetByClientID(client_id);
2202 return socket == nullptr ? "" : socket->GetPeerPublicKey();
2203}
2204
2205
2212{
2213 assert(c != nullptr);
2214
2215 if (!_network_server) return;
2216
2217 if (ci != nullptr) {
2218 /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
2219 ci->client_playas = c->index;
2221
2222 /*
2223 * This function is called from a command, but is only called for the server.
2224 * The client information is managed out-of-band from the commands, so to not have a
2225 * different state/president/company name in the different clients, we need to
2226 * circumvent the normal ::Post logic and go directly to sending the command.
2227 */
2228 Command<Commands::CompanyAllowListControl>::SendNet(STR_NULL, c->index, CompanyAllowListCtrlAction::AddKey, ci->public_key);
2229 Command<Commands::RenamePresident>::SendNet(STR_NULL, c->index, ci->client_name);
2230
2232 }
2233}
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
Default implementation for the authorized key handler.
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.
bool Contains(std::string_view key) const
Check whether the given key is contains in these authorized keys.
Definition network.cpp:180
bool IsPendingDeletion() const
Is this pending for deletion and as such should not be accessed anymore.
Definition tcp_game.h:571
NetworkGameSocketHandler(SOCKET s)
Create a new socket for the game connection.
Definition tcp_game.cpp:28
uint32_t last_frame
Last frame we have executed.
Definition tcp_game.h:528
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition tcp_game.h:557
std::optional< std::string_view > ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
ClientID client_id
Client identifier.
Definition tcp_game.h:527
CommandQueue incoming_queue
The command-queue awaiting handling.
Definition tcp_game.h:530
std::chrono::steady_clock::time_point last_packet
Time we received the last frame.
Definition tcp_game.h:531
void SetInfo(NetworkClientInfo *info)
Sets the client info for this socket handler.
Definition tcp_game.h:547
uint32_t last_frame_server
Last frame the server has executed.
Definition tcp_game.h:529
NetworkClientInfo * info
Client info related to this socket.
Definition tcp_game.h:143
void SendCommand(Packet &p, const CommandPacket &cp)
Sends a command over the network.
void DeferDeletion()
Mark this socket handler for deletion, once iterating the socket handlers is done.
Definition tcp_game.cpp:189
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition core.h:72
std::unique_ptr< class NetworkEncryptionHandler > send_encryption_handler
The handler for encrypting sent packets.
Definition core.h:48
std::unique_ptr< class NetworkEncryptionHandler > receive_encryption_handler
The handler for decrypting received packets.
Definition core.h:47
virtual std::unique_ptr< Packet > ReceivePacket()
Receives a packet for the given client.
Definition tcp.cpp:118
SOCKET sock
The socket currently connected to.
Definition tcp.h:35
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:57
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition tcp.cpp:75
Class for handling the server side of the game connection.
static std::string_view GetName()
Get the name used by the listener.
NetworkRecvStatus ReceiveClientGameInfo(Packet &p) override
Request game information.
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 SendQuit(ClientID client_id)
Tell the client another client quit.
NetworkRecvStatus ReceiveClientIdentify(Packet &p) override
The client tells the server about the identity of the client: string Name of the client (max NETWORK_...
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 SendRConResult(uint16_t colour, std::string_view command)
Send the result of a console action.
NetworkRecvStatus ReceiveClientAck(Packet &p) override
Tell the server we are done with this frame: uint32_t Current frame counter of the client.
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, std::string_view msg, int64_t data)
Send a chat message.
NetworkRecvStatus SendWelcome()
Send the client a welcome message with some basic information.
NetworkRecvStatus SendAuthRequest()
Request the game password.
std::string GetClientName() const
Get the name of the client, if the user did not send it yet, Client ID is used.
NetworkRecvStatus ReceiveClientRemoteConsoleCommand(Packet &p) override
Send an RCon command to the server: string RCon password.
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 ReceiveClientSetName(Packet &p) override
Gives the client a new name: string New name of the client.
NetworkRecvStatus SendGameInfo()
Send the client information about the server.
NetworkRecvStatus SendJoin(ClientID client_id)
Tell that a client joined.
~ServerNetworkGameSocketHandler() override
Clear everything related to this client.
NetworkRecvStatus ReceiveClientChat(Packet &p) override
Sends a chat-packet to the server: uint8_t ID of the action (see NetworkAction).
NetworkRecvStatus ReceiveClientNewGRFsChecked(Packet &p) override
Tell the server that we have the required GRFs.
std::string peer_public_key
The public key of our client.
NetworkRecvStatus ReceiveClientGetMap(Packet &p) override
Request the map from the server.
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 SendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
Send a chat message from external source.
ServerNetworkGameSocketHandler(ClientPoolID index, SOCKET s)
Create a new socket for the server side of the game connection.
NetworkRecvStatus SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
Tell the client another client quit with an error.
NetworkAddress client_address
IP-address of the client (so they can be banned).
NetworkRecvStatus SendNewGame()
Tell the client we're starting a new game.
NetworkRecvStatus ReceiveClientCommand(Packet &p) override
Send a DoCommand to the Server: uint8_t ID of the company (0..MAX_COMPANIES-1).
NetworkRecvStatus SendSync()
Request the client to sync.
std::unique_ptr< class NetworkAuthenticationServerHandler > authentication_handler
The handler for the authentication.
NetworkRecvStatus ReceiveClientJoin(Packet &p) override
Try to join the server: string OpenTTD revision (norev0000 if no revision).
NetworkRecvStatus ReceiveClientError(Packet &p) override
The client made an error and is quitting the game.
NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id)
Tell that a client moved to another company.
NetworkRecvStatus SendError(NetworkErrorCode error, std::string_view reason={})
Send an error to the client, and close its connection.
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override
Close the network connection due to the given status.
NetworkRecvStatus SendMap()
This sends the map to the client.
uint32_t last_token_frame
The last frame we received the right token.
NetworkRecvStatus SendShutdown()
Tell the client we're shutting down.
NetworkRecvStatus ReceiveClientMapOk(Packet &p) override
Tell the server that we are done receiving/loading the map.
NetworkRecvStatus ReceiveClientQuit(Packet &p) override
The client is quitting the game.
ClientStatus status
Status of this client.
void CheckNextClientToSendMap(NetworkClientSocket *ignore_cs=nullptr)
Find the next candidate for joining, and start the joining process for that client.
NetworkRecvStatus SendNewGRFCheck()
Send the check for the NewGRFs.
NetworkRecvStatus ReceiveClientAuthenticationResponse(Packet &p) override
Send the response to the authentication request: 32 * uint8_t Public key of the client.
std::string_view GetClientIP()
Get the IP address/hostname of the connected client.
NetworkRecvStatus SendConfigUpdate()
Send an update about the max company/spectator counts.
NetworkRecvStatus SendWait()
Tell the client that its put in a waiting queue.
NetworkRecvStatus ReceiveClientMove(Packet &p) override
Request the server to move this client into another company: uint8_t ID of the company the client wan...
NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the client to execute.
Template for TCP listeners.
Definition tcp_listen.h:29
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)
Get the command flags associated with the given command.
Definition command.cpp:113
Functions related to commands.
@ 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.
@ CompanyControl
used in multiplayer to create a new companies etc.
@ CompanyAllowListControl
Used in multiplayer to add/remove a client's public key to/from the company's allow list.
Definition of stuff that is very close to a company, like the company struct itself.
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...
Command definitions related to companies.
Functions related to companies.
GUI Functions related to companies.
CompanyCtrlAction
The action to do with Commands::CompanyControl.
@ New
Create a new company.
@ Delete
Delete a company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
@ AddKey
Create a public key.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ Autoclean
The company is removed due to autoclean.
static const size_t TCP_MTU
Number of bytes we can pack in a single TCP packet.
Definition config.h:43
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:56
static const uint NETWORK_CHAT_LENGTH
The maximum length of a chat message, in bytes including '\0'.
Definition config.h:59
static const uint NETWORK_REVISION_LENGTH
The maximum length of the revision, in bytes including '\0'.
Definition config.h:54
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition config.h:57
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:55
void IConsoleCmdExec(std::string_view command_string, const uint recurse_count)
Execute a given command passed to us.
Definition console.cpp:271
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition console.cpp:90
Console functions used outside of the console code.
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_WARNING
Colour for warning lines.
static const TextColour CC_DEFAULT
Default colour of the console.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition core.h:21
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition core.h:26
@ NETWORK_RECV_STATUS_SERVER_ERROR
The server told us we made an error.
Definition core.h:28
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition core.h:22
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition core.h:27
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
#define DECLARE_INCREMENT_DECREMENT_OPERATORS(enum_type)
For some enums it is useful to have pre/post increment/decrement operators.
Definition enum_type.hpp:86
@ Savegame
old or new savegame
Definition fileio_type.h:19
@ Scenario
old or new scenario
Definition fileio_type.h:20
@ Heightmap
heightmap file
Definition fileio_type.h:21
Functions related to world/map generation.
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:50
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition gfx_type.h:370
uint32_t _last_sync_frame
Used in the server to store the last time a sync packet was sent to clients.
Definition network.cpp:81
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve a short translateable string of the error code.
Definition network.cpp:328
ClientID _redirect_console_to_client
If not invalid, redirect the console output to a client.
Definition network.cpp:73
uint32_t _frame_counter
The current frame.
Definition network.cpp:80
StringList _network_ban_list
The banned clients.
Definition network.cpp:77
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:70
bool _network_server
network-server is active
Definition network.cpp:68
uint32_t _sync_seed_1
Seed to compare during sync checks.
Definition network.cpp:83
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, std::string_view name, std::string_view str, StringParameter &&data)
Writes a text-message to the console and the chat box.
Definition network.cpp:244
uint NetworkCalculateLag(const NetworkClientSocket *cs)
Calculate the frame-lag of a client.
Definition network.cpp:299
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:91
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:79
void NetworkAdminClientUpdate(const NetworkClientInfo *ci)
Notify the admin network of a client update (if they did opt in for the respective update).
void NetworkAdminClientQuit(ClientID client_id)
Notify the admin network that a client quit (if they have opt in for the respective update).
void 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 NetworkAdminChat(NetworkAction action, NetworkChatDestinationType desttype, ClientID client_id, std::string_view msg, int64_t data, bool from_admin)
Send chat to the admin network (if they did opt in for the respective update).
void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code)
Notify the admin network of a client error (if they have opt in for the respective update).
Server part of the admin network protocol.
Base core network types and some helper functions to access them.
bool NetworkIsValidClientName(std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
void NetworkSyncCommandQueue(NetworkClientSocket *cs)
Sync our local command queue to the command queue of the given socket.
NetworkAuthenticationMethod
The authentication method that can be used.
@ X25519_PAKE
Authentication using x25519 password-authenticated key agreement.
@ X25519_AuthorizedKey
Authentication using x22519 key exchange and authorized keys.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
void NetworkServerSendChat(NetworkAction action, NetworkChatDestinationType type, int dest, std::string_view msg, ClientID from_id, int64_t data=0, bool from_admin=false)
Send an actual chat message.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
TypedIndexContainer< std::array< NetworkCompanyStats, MAX_COMPANIES >, CompanyID > NetworkCompanyStatsArray
Container with statistics for all possible companies.
void SerializeNetworkGameInfo(Packet &p, const NetworkServerGameInfo &info, bool send_newgrf_names)
Serializes the NetworkGameInfo struct to the packet.
const NetworkServerGameInfo & GetCurrentNetworkServerGameInfo()
Get the NetworkServerGameInfo structure with the latest information of the server.
void SerializeGRFIdentifier(Packet &p, const GRFIdentifier &grf)
Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet.
void FillStaticNetworkServerGameInfo()
Fill a NetworkServerGameInfo structure with the static content, or things that are so static they can...
NetworkServerGameInfo _network_game_info
Information about our game.
bool IsNetworkCompatibleVersion(std::string_view other)
Checks whether the given version string is compatible with our version.
Convert NetworkGameInfo to Packet and back.
class ServerNetworkGameSocketHandler NetworkClientSocket
Class for handling the server side of the game connection.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler
Provides the authorized key handling for the game authentication.
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
Change the client name of the given client.
void NetworkServerSendExternalChat(std::string_view source, TextColour colour, std::string_view user, std::string_view msg)
Send a chat message from external source.
static IntervalTimer< TimerGameRealtime > _network_restart_map_timer({std::chrono::hours::zero(), TimerGameRealtime::Trigger::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.
void NetworkPrintClients()
Print all the clients to the console.
void NetworkServerUpdateGameInfo()
Update the server's NetworkServerGameInfo due to changes in settings.
static const IntervalTimer< TimerGameEconomy > _network_monthly({TimerGameEconomy::Trigger::Month, TimerGameEconomy::Priority::None}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(AdminUpdateFrequency::Monthly);})
Economy monthly "callback".
NetworkCompanyStatsArray NetworkGetCompanyStats()
Get the company stats.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
void NetworkServerSendChat(NetworkAction action, NetworkChatDestinationType desttype, int dest, std::string_view msg, ClientID from_id, int64_t data, bool from_admin)
Send an actual chat message.
NetworkClientSocketPool _networkclientsocket_pool
Make very sure the preconditions given in network_type.h are actually followed.
void NetworkServerSendConfigUpdate()
Send Config Update.
static const IntervalTimer< TimerGameEconomy > _network_quarterly({TimerGameEconomy::Trigger::Quarter, TimerGameEconomy::Priority::None}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(AdminUpdateFrequency::Quarterly);})
Quarterly "callback".
static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
Determine the NetworkErrorCode for a failure of a given authentication method.
static const IntervalTimer< TimerGameCalendar > _calendar_network_yearly({ TimerGameCalendar::Trigger::Year, TimerGameCalendar::Priority::None }, [](auto) { if(!_network_server) return;NetworkCheckRestartMapYear();})
Calendar yearly "callback".
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
static NetworkAuthenticationDefaultPasswordProvider _password_provider
Provides the password validation for the game's password.
static const IntervalTimer< TimerGameEconomy > _economy_network_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::None}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::Annually);})
Economy yearly "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.
void NetworkServerKickClient(ClientID client_id, std::string_view reason)
Kick a single client.
static void NetworkCheckRestartMapYear()
Check if we want to restart the map based on the year.
bool NetworkMakeClientNameUnique(std::string &name)
Check whether a name is unique, and otherwise try to make it unique.
static ClientID _network_client_id
The identifier counter for new clients (is never decreased).
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
Get the public key of the client with the given id.
static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
Handle the command-queue of a socket.
static const IntervalTimer< TimerGameEconomy > _economy_network_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::None}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::Daily);})
Daily "callback".
static const IntervalTimer< TimerGameEconomy > _network_weekly({TimerGameEconomy::Trigger::Week, TimerGameEconomy::Priority::None}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(AdminUpdateFrequency::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 NetworkServerSendRcon(ClientID client_id, TextColour colour_code, std::string_view string)
Send an rcon reply to the client.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
Ban, or kick, everyone joined from the given client's IP.
void NetworkServer_Tick(bool send_frame)
This is called every tick if this is a _network_server.
static void NetworkAutoCleanCompanies()
Remove companies that have not been used depending on the autoclean_companies setting and values for ...
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler
Provides the authorized key validation for rcon.
Server part of the network protocol.
ServerNetworkGameSocketHandler NetworkClientSocket
Make the code look slightly nicer/simpler.
NetworkClientSocketPool _networkclientsocket_pool
Make very sure the preconditions given in network_type.h are actually followed.
Pool< NetworkClientSocket, ClientPoolID, 8, PoolType::NetworkClient > NetworkClientSocketPool
Pool with all client sockets.
NetworkVehicleType
Vehicletypes in the order they are send in info packets.
@ Bus
A road vehicle that stops at bus stops.
@ Truck
A road vehicle that stops at truck stops.
@ Aircraft
An airplane or helicopter.
NetworkErrorCode
The error codes we send around in the protocols.
@ WrongRevision
The client is using the wrong revision.
@ Cheater
The client is trying control companies in a way they are not supposed to.
@ TimeoutPassword
The client has timed out providing a password.
@ TooManyCommands
The client has sent too many commands in a short time.
@ TimeoutComputer
The client has timed out because the computer could not keep up with the server.
@ TimeoutMap
The client has timed out because it took too long to download the map.
@ NotAuthorized
The client tried to do something there are not authorized to.
@ ServerFull
The server is full.
@ InvalidClientName
The client tried to set an invalid name.
@ TimeoutJoin
The client has timed out because getting up to speed with the server failed.
@ NotOnAllowList
The client is not on the allow list.
@ WrongPassword
The client entered a wrong password.
@ NotExpected
The request/packet was not expected in the current state.
@ Kicked
The client got kicked.
@ ConnectionLost
Connection to the client was lost.
@ IllegalPacket
A packet was received that has invalid content.
@ NameInUse
The client has a duplicate name (and we couldn't make it unique).
@ CompanyMismatch
The client was impersonating another company.
NetworkAction
Actions that can be used for NetworkTextMessage.
@ ChatExternal
An external application sent a message over the admin port.
@ ServerMessage
The server sent a message.
@ ClientKicked
A client got kicked.
@ ChatTeam
A chat sent to all clients of a team/company.
@ ClientNameChange
A client changed their name.
@ ClientJoin
A client joined the server.
@ CompanySpectator
A client joined the spectators.
@ ChatClient
A chat sent to a specific client.
@ ChatBroadcast
A chat broadcast to all clients.
@ ClientLeave
A client left the server.
@ CompanyNew
A client created an joined a new company.
@ CompanyJoin
A client joined an existing company.
static const uint MAX_CLIENTS
How many clients can we have.
NetworkChatDestinationType
Destination of our chat messages.
@ Client
Send message/notice to only a certain client (Private).
@ Team
Send message/notice to everyone playing the same company (Team).
@ Broadcast
Send message/notice to all clients (All).
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.
PoolID< uint16_t, struct ClientPoolIDTag, MAX_CLIENTS+1, 0xFFFF > ClientPoolID
Indices into the client related pools.
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
Functions related to order backups.
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Pseudo random number generator.
Declaration of OTTD revision dependent variables.
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
void SlError(StringID string, const std::string &extra_msg)
Error handler.
Definition saveload.cpp:339
SaveOrLoadResult SaveWithFilter(std::shared_ptr< SaveFilter > writer, bool threaded)
Save the game using a (writer) filter.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:78
Functions/types related to saving and loading games.
@ SL_OK
completed successfully
Definition saveload.h:425
Declaration of filters used for saving and loading savegames.
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:62
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Base classes/functions for stations.
@ 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.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
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.
NetworkAuthorizedKeys allow_list
Public keys of clients that are allowed to join this company.
bool allow_any
Set if anyone is allowed to join this company.
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?
Statistics and caches on the vehicles in a group.
Definition group.h:25
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:118
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.
NetworkVehicleTypeArray num_station
How many stations are there of this type?
static void ResetUser(uint32_t user)
Reset an user's OrderBackup if needed.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
std::unique_ptr< Packet > current
The packet we're currently writing to.
PacketWriter(ServerNetworkGameSocketHandler *cs)
Create the packet writer.
size_t total_size
Total size of the compressed savegame.
std::condition_variable exit_sig
Signal for threaded destruction of this packet writer.
void Finish() override
Prepare everything to finish writing the savegame.
~PacketWriter() override
Make sure everything is cleaned up under lock.
ServerNetworkGameSocketHandler * cs
Socket we are associated with.
std::mutex mutex
Mutex for making threaded saving safe.
void Destroy()
Begin the destruction of this packet writer.
bool TransferToNetworkQueue()
Transfer all packets from here to the network's queue while holding the lock on our mutex.
std::deque< std::unique_ptr< Packet > > packets
Packet queue of the savegame; send these "slowly" to the client. Cannot be a std::queue as we want to...
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition packet.cpp:362
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
Definition packet.cpp:345
std::string Recv_string(size_t length, StringValidationSettings settings=StringValidationSetting::ReplaceWithQuestionMark)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
Definition packet.cpp:423
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:316
static Pool::IterateWrapper< NetworkClientSocket > Iterate(size_t from=0)
static Company * Get(auto index)
static Company * GetIfValid(auto index)
bool IsBus() const
Check whether a roadvehicle is a bus.
SaveFilter(std::shared_ptr< SaveFilter > chain)
Initialise this filter.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
static RoadVehicle * From(Vehicle *v)
Station data structure.
Vehicle data structure.
@ SPS_CLOSED
The connection got closed.
Definition tcp.h:22
@ ServerFull
The server tells the admin it cannot accept the admin.
Definition tcp_admin.h:35
@ ServerBanned
The server tells the admin it is banned.
Definition tcp_admin.h:36
@ Annually
The admin gets information about this on a yearly basis.
Definition tcp_admin.h:102
@ Weekly
The admin gets information about this on a weekly basis.
Definition tcp_admin.h:99
@ Monthly
The admin gets information about this on a monthly basis.
Definition tcp_admin.h:100
@ Quarterly
The admin gets information about this on a quarterly basis.
Definition tcp_admin.h:101
@ Daily
The admin gets information about this on a daily basis.
Definition tcp_admin.h:98
PacketGameType
Enum with all types of TCP packets.
Definition tcp_game.h:22
@ ServerAuthenticationRequest
The server requests the client to authenticate using a number of methods.
Definition tcp_game.h:60
@ ServerClientInfo
Server sends you information about a client.
Definition tcp_game.h:73
@ ServerShutdown
The server is shutting down.
Definition tcp_game.h:47
@ ServerMapDone
Server tells it has just sent the last bits of the map to the client.
Definition tcp_game.h:81
@ ServerMapBegin
Server tells the client that it is beginning to send the map.
Definition tcp_game.h:78
@ ServerFrame
Server tells the client what frame it is in, and thus to where the client may progress.
Definition tcp_game.h:93
@ ServerMapData
Server sends bits of the map to the client.
Definition tcp_game.h:80
@ ServerClientJoined
Tells clients that a new client has joined.
Definition tcp_game.h:84
@ ServerGameInfo
Information about the server.
Definition tcp_game.h:42
@ ServerMapSize
Server tells the client what the (compressed) size of the map is.
Definition tcp_game.h:79
@ ServerMove
Server tells everyone that someone is moved to another company.
Definition tcp_game.h:112
@ ServerQuit
A server tells that a client has quit.
Definition tcp_game.h:120
@ ServerError
Server sending an error message to the client.
Definition tcp_game.h:35
@ ServerSync
Server tells the client what the random state should be.
Definition tcp_game.h:95
@ ServerConfigurationUpdate
Some network configuration important to the client changed.
Definition tcp_game.h:116
@ ServerRemoteConsoleCommand
Response of the executed command on the server.
Definition tcp_game.h:108
@ ServerExternalChat
Server distributing the message from external source.
Definition tcp_game.h:104
@ ServerErrorQuit
A server tells that a client has hit an error and did quit.
Definition tcp_game.h:122
@ ServerWelcome
Server welcomes you and gives you your ClientID.
Definition tcp_game.h:72
@ ServerCommand
Server distributes a command to (all) the clients.
Definition tcp_game.h:99
@ ServerChat
Server distributing the message of a client (or itself).
Definition tcp_game.h:103
@ ServerCheckNewGRFs
Server sends NewGRF IDs and MD5 checksums for the client to check.
Definition tcp_game.h:68
@ ServerWaitForMap
Server tells the client there are some people waiting for the map as well.
Definition tcp_game.h:77
@ ServerEnableEncryption
The server tells that authentication has completed and requests to enable encryption with the keys of...
Definition tcp_game.h:62
@ ServerNewGame
The server is preparing to start a new game.
Definition tcp_game.h:46
SocketList TCPListenHandler< Tsocket, EnumPacketType, Tfull_packet, Tban_packet >::sockets
Instantiate the sockets.
Definition tcp_listen.h:181
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the real time game-timer.
@ 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:3322
@ WC_CLIENT_LIST
Client list; Window numbers: