OpenTTD Source 20260311-master-g511d3794ce
network_client.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 "network_gui.h"
14#include "../command_func.h"
15#include "../console_func.h"
16#include "../strings_func.h"
17#include "../window_func.h"
18#include "../company_func.h"
19#include "../company_base.h"
20#include "../company_gui.h"
21#include "../company_cmd.h"
25#include "../gfx_func.h"
26#include "../error.h"
27#include "../rev.h"
28#include "network.h"
29#include "network_base.h"
30#include "network_client.h"
31#include "network_gamelist.h"
33#include "../thread.h"
35
36#include "table/strings.h"
37
38#include "../safeguards.h"
39
40/* This file handles all the client-commands */
41
44 using Buffer = std::deque<uint8_t>;
45
47 Buffer::const_iterator iterator;
48 size_t read_bytes = 0;
49
52 {
53 }
54
60 {
61 assert(this->read_bytes == 0);
62 p.TransferOut([this](std::span<const uint8_t> source) {
63 std::ranges::copy(source, std::back_inserter(this->buffer));
64 return source.size();
65 });
66 }
67
68 size_t Read(uint8_t *rbuf, size_t size) override
69 {
70 /* Limit the amount to read to whatever we still have. */
71 size_t read_size = std::min(this->buffer.size() - this->read_bytes, size);
72
73 std::copy_n(this->iterator, read_size, rbuf);
74 std::advance(this->iterator, read_size);
75 this->read_bytes += read_size;
76
77 return read_size;
78 }
79
80 void Reset() override
81 {
82 this->read_bytes = 0;
83 this->iterator = this->buffer.cbegin();
84 }
85};
86
87
92{
93 static FiosNumberedSaveName _netsave_ctr("netsave");
94 DoAutoOrNetsave(_netsave_ctr);
95}
96
97
108
117
119{
121 if (this->IsPendingDeletion()) return status;
122
123 assert(this->sock != INVALID_SOCKET);
124
125 if (!this->HasClientQuit()) {
126 Debug(net, 3, "Closed client connection {}", this->client_id);
127
128 this->SendPackets(true);
129
130 /* Wait a number of ticks so our leave message can reach the server.
131 * This is especially needed for Windows servers as they seem to get
132 * the "socket is closed" message before receiving our leave message,
133 * which would trigger the server to close the connection as well. */
135 }
136
137 this->DeferDeletion();
138
139 return status;
140}
141
147{
148 if (this->IsPendingDeletion()) return;
149
150 /* We just want to close the connection.. */
153 this->CloseConnection(res);
154 _networking = false;
155
157 return;
158 }
159
160 /* Send a CLIENT_ERROR to the server, so it knows we are disconnected (and why!) */
161 NetworkErrorCode errorno;
162 switch (res) {
166 default: errorno = NetworkErrorCode::General; break;
167 }
168
171 /* This means the server closed the connection. Emergency save is
172 * already created if this was appropriate during handling of the
173 * disconnect. */
174 this->CloseConnection(res);
175 } else {
176 /* This means we as client made a boo-boo. */
177 SendError(errorno);
178
179 /* Close connection before we make an emergency save, as the save can
180 * take a bit of time; better that the server doesn't stall while we
181 * are doing the save, and already disconnects us. */
182 this->CloseConnection(res);
184 }
185
187
188 if (_game_mode != GM_MENU) _switch_mode = SM_MENU;
189 _networking = false;
190}
191
192
199{
200 if (my_client->CanSendReceive()) {
201 NetworkRecvStatus res = my_client->ReceivePackets();
202 if (res != NETWORK_RECV_STATUS_OKAY) {
203 /* The client made an error of which we can not recover.
204 * Close the connection and drop back to the main menu. */
205 my_client->ClientError(res);
206 return false;
207 }
208 }
209 return _networking;
210}
211
214{
215 my_client->SendPackets();
216 if (my_client != nullptr) my_client->CheckConnection();
217}
218
224{
226
228
230
231 /* Check if we are in sync! */
232 if (_sync_frame != 0) {
234#ifdef NETWORK_SEND_DOUBLE_SEED
235 if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
236#else
237 if (_sync_seed_1 != _random.state[0]) {
238#endif
239 ShowNetworkError(STR_NETWORK_ERROR_DESYNC);
240 Debug(desync, 1, "sync_err: {:08x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract);
241 Debug(net, 0, "Sync error detected");
243 return false;
244 }
245
246 /* If this is the first time we have a sync-frame, we
247 * need to let the server know that we are ready and at the same
248 * frame as it is.. so we can start playing! */
250 _network_first_time = false;
251 SendAck();
252 }
253
254 _sync_frame = 0;
255 } else if (_sync_frame < _frame_counter) {
256 Debug(net, 1, "Missed frame for sync-test: {} / {}", _sync_frame, _frame_counter);
257 _sync_frame = 0;
258 }
259 }
260
261 return true;
262}
263
264
267
269static uint32_t last_ack_frame;
270
275
278
279/***********
280 * Sending functions
281 ************/
282
288{
289 Debug(net, 9, "Client::SendJoin()");
290
291 Debug(net, 9, "Client::status = JOIN");
292 my_client->status = STATUS_JOIN;
293 Debug(net, 9, "Client::join_status = Authorizing");
296
297 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_JOIN);
298 p->Send_string(GetNetworkRevisionString());
299 p->Send_uint32(_openttd_newgrf_version);
300 my_client->SendPacket(std::move(p));
301
303}
304
310{
311 Debug(net, 9, "Client::SendIdentify()");
312
313 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_IDENTIFY);
314 p->Send_string(_settings_client.network.client_name); // Client name
315 p->Send_uint8(_network_join.company); // PlayAs
316 my_client->SendPacket(std::move(p));
318}
319
325{
326 Debug(net, 9, "Client::SendNewGRFsOk()");
327
328 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_NEWGRFS_CHECKED);
329 my_client->SendPacket(std::move(p));
331}
332
338{
339 Debug(net, 9, "Client::SendAuthResponse()");
340
341 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_AUTH_RESPONSE);
342 my_client->authentication_handler->SendResponse(*p);
343 my_client->SendPacket(std::move(p));
344
346}
347
353{
354 Debug(net, 9, "Client::SendGetMap()");
355
356 Debug(net, 9, "Client::status = MAP_WAIT");
357 my_client->status = STATUS_MAP_WAIT;
358
359 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_GETMAP);
360 my_client->SendPacket(std::move(p));
362}
363
369{
370 Debug(net, 9, "Client::SendMapOk()");
371
372 Debug(net, 9, "Client::status = ACTIVE");
373 my_client->status = STATUS_ACTIVE;
374
375 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MAP_OK);
376 my_client->SendPacket(std::move(p));
378}
379
385{
386 Debug(net, 9, "Client::SendAck()");
387
388 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ACK);
389
390 p->Send_uint32(_frame_counter);
391 p->Send_uint8 (my_client->token);
392 my_client->SendPacket(std::move(p));
394}
395
402{
403 Debug(net, 9, "Client::SendCommand(): cmd={}", cp.cmd);
404
405 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_COMMAND);
406 my_client->NetworkGameSocketHandler::SendCommand(*p, cp);
407
408 my_client->SendPacket(std::move(p));
410}
411
421NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, std::string_view msg, int64_t data)
422{
423 Debug(net, 9, "Client::SendChat(): action={}, type={}, dest={}", action, type, dest);
424
425 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_CHAT);
426
427 p->Send_uint8 (action);
428 p->Send_uint8 (type);
429 p->Send_uint32(dest);
430 p->Send_string(msg);
431 p->Send_uint64(data);
432
433 my_client->SendPacket(std::move(p));
435}
436
443{
444 Debug(net, 9, "Client::SendError(): errorno={}", errorno);
445
446 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ERROR);
447
448 p->Send_uint8(to_underlying(errorno));
449 my_client->SendPacket(std::move(p));
451}
452
459{
460 Debug(net, 9, "Client::SendSetName()");
461
462 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_SET_NAME);
463
464 p->Send_string(name);
465 my_client->SendPacket(std::move(p));
467}
468
474{
475 Debug(net, 9, "Client::SendQuit()");
476
477 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_QUIT);
478
479 my_client->SendPacket(std::move(p));
481}
482
489NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(std::string_view pass, std::string_view command)
490{
491 Debug(net, 9, "Client::SendRCon()");
492
493 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_RCON);
494 p->Send_string(pass);
495 p->Send_string(command);
496 my_client->SendPacket(std::move(p));
498}
499
506{
507 Debug(net, 9, "Client::SendMove(): company={}", company);
508
509 auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MOVE);
510 p->Send_uint8(company);
511 my_client->SendPacket(std::move(p));
513}
514
520{
521 return my_client != nullptr && my_client->status == STATUS_ACTIVE;
522}
523
524
525/***********
526 * Receiving functions
527 ************/
528
529extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, std::shared_ptr<struct LoadFilter> lf);
530
532{
533 Debug(net, 9, "Client::Receive_SERVER_FULL()");
534
535 /* We try to join a server which is full */
536 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SERVER_FULL), {}, WL_CRITICAL);
537
539}
540
542{
543 Debug(net, 9, "Client::Receive_SERVER_BANNED()");
544
545 /* We try to join a server where we are banned */
546 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SERVER_BANNED), {}, WL_CRITICAL);
547
549}
550
551/* This packet contains info about the client (playas and name)
552 * as client we save this in NetworkClientInfo, linked via 'client_id'
553 * which is always an unique number on a server. */
555{
558 CompanyID playas = (CompanyID)p.Recv_uint8();
559
560 Debug(net, 9, "Client::Receive_SERVER_CLIENT_INFO(): client_id={}, playas={}", client_id, playas);
561
562 std::string name = p.Recv_string(NETWORK_NAME_LENGTH);
563 std::string public_key = p.Recv_string(NETWORK_PUBLIC_KEY_LENGTH);
564
567 /* The server validates the name when receiving it from clients, so when it is wrong
568 * here something went really wrong. In the best case the packet got malformed on its
569 * way too us, in the worst case the server is broken or compromised. */
571
573 if (ci != nullptr) {
574 if (playas == ci->client_playas && name != ci->client_name) {
575 /* Client name changed, display the change */
576 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, name);
577 } else if (playas != ci->client_playas) {
578 /* The client changed from client-player..
579 * Do not display that for now */
580 }
581
582 /* Make sure we're in the company the server tells us to be in,
583 * for the rare case that we get moved while joining. */
585
586 ci->client_playas = playas;
587 ci->client_name = std::move(name);
588 ci->public_key = std::move(public_key);
589
591
593 }
594
595 /* There are at most as many ClientInfo as ClientSocket objects in a
596 * server. Having more info than a server can have means something
597 * has gone wrong somewhere, i.e. the server has more info than it
598 * has actual clients. That means the server is feeding us an invalid
599 * state. So, bail out! This server is broken. */
601
602 /* We don't have this client_id yet, find an empty client_id, and put the data there */
604 ci->client_playas = playas;
605 if (client_id == _network_own_client_id) this->SetInfo(ci);
606
607 ci->client_name = std::move(name);
608 ci->public_key = std::move(public_key);
609
611
613}
614
622{
623 switch (error) {
631 default:
632 return STR_NETWORK_ERROR_LOSTCONNECTION;
633
638 return STR_NETWORK_ERROR_SERVER_ERROR;
639
640 case NetworkErrorCode::WrongRevision: return STR_NETWORK_ERROR_WRONG_REVISION;
641 case NetworkErrorCode::WrongPassword: return STR_NETWORK_ERROR_WRONG_PASSWORD;
642 case NetworkErrorCode::Kicked: return STR_NETWORK_ERROR_KICKED;
643 case NetworkErrorCode::Cheater: return STR_NETWORK_ERROR_CHEATER;
644 case NetworkErrorCode::ServerFull: return STR_NETWORK_ERROR_SERVER_FULL;
645 case NetworkErrorCode::TooManyCommands: return STR_NETWORK_ERROR_TOO_MANY_COMMANDS;
646 case NetworkErrorCode::TimeoutPassword: return STR_NETWORK_ERROR_TIMEOUT_PASSWORD;
647 case NetworkErrorCode::TimeoutComputer: return STR_NETWORK_ERROR_TIMEOUT_COMPUTER;
648 case NetworkErrorCode::TimeoutMap: return STR_NETWORK_ERROR_TIMEOUT_MAP;
649 case NetworkErrorCode::TimeoutJoin: return STR_NETWORK_ERROR_TIMEOUT_JOIN;
650 case NetworkErrorCode::InvalidClientName: return STR_NETWORK_ERROR_INVALID_CLIENT_NAME;
651 case NetworkErrorCode::NotOnAllowList: return STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST;
652 }
653}
654
656{
657 NetworkErrorCode error = static_cast<NetworkErrorCode>(p.Recv_uint8());
658 Debug(net, 9, "Client::Receive_SERVER_ERROR(): error={}", error);
659
661 /* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
662 if (error == NetworkErrorCode::Kicked && p.CanReadFromPacket(1)) {
664 GetEncodedString(STR_NETWORK_ERROR_KICK_MESSAGE, p.Recv_string(NETWORK_CHAT_LENGTH)),
666 } else {
668 }
669
670 /* Perform an emergency save if we had already entered the game */
672
674}
675
677{
679
680 uint grf_count = p.Recv_uint8();
682
683 Debug(net, 9, "Client::Receive_SERVER_CHECK_NEWGRFS(): grf_count={}", grf_count);
684
685 /* Check all GRFs */
686 for (; grf_count > 0; grf_count--) {
689
690 /* Check whether we know this GRF */
691 const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, &c.md5sum);
692 if (f == nullptr) {
693 /* We do not know this GRF, bail out of initialization */
694 Debug(grf, 0, "NewGRF {:08X} not found; checksum {}", std::byteswap(c.grfid), FormatArrayAsHex(c.md5sum));
696 }
697 }
698
699 if (ret == NETWORK_RECV_STATUS_OKAY) {
700 /* Start receiving the map */
701 return SendNewGRFsOk();
702 }
703
704 /* NewGRF mismatch, bail out */
705 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NEWGRF_MISMATCH), {}, WL_CRITICAL);
706 return ret;
707}
708
711 void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override
712 {
713 if (!_network_join.server_password.empty()) {
714 request->Reply(_network_join.server_password);
715 } else {
716 ShowNetworkNeedPassword(std::move(request));
717 }
718 }
719};
720
722{
724 Debug(net, 9, "Client::status = AUTH_GAME");
725 this->status = STATUS_AUTH_GAME;
726
727 Debug(net, 9, "Client::Receive_SERVER_AUTH_REQUEST()");
728
729 if (this->authentication_handler == nullptr) {
730 this->authentication_handler = NetworkAuthenticationClientHandler::Create(std::make_shared<ClientGamePasswordRequestHandler>(),
731 _settings_client.network.client_secret_key, _settings_client.network.client_public_key);
732 }
733 switch (this->authentication_handler->ReceiveRequest(p)) {
735 return SendAuthResponse();
736
739
741 default:
743 }
744}
745
747{
749
750 Debug(net, 9, "Client::Receive_SERVER_ENABLE_ENCRYPTION()");
751
752 if (!this->authentication_handler->ReceiveEnableEncryption(p)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
753
754 this->receive_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
755 this->send_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
756 this->authentication_handler = nullptr;
757
758 Debug(net, 9, "Client::status = ENCRYPTED");
759 this->status = STATUS_ENCRYPTED;
760
761 return this->SendIdentify();
762}
763
765{
767 Debug(net, 9, "Client::status = AUTHORIZED");
769
771
772 Debug(net, 9, "Client::Receive_SERVER_WELCOME(): client_id={}", _network_own_client_id);
773
774 /* Start receiving the map */
775 return SendGetMap();
776}
777
779{
780 /* We set the internal wait state when requesting the map. */
782
783 Debug(net, 9, "Client::Receive_SERVER_WAIT()");
784
785 /* But... only now we set the join status to waiting, instead of requesting. */
786 Debug(net, 9, "Client::join_status = Waiting");
790
792}
793
795{
797 Debug(net, 9, "Client::status = MAP");
798 this->status = STATUS_MAP;
799
800 if (this->savegame != nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
801
802 this->savegame = std::make_shared<PacketReader>();
803
805
806 Debug(net, 9, "Client::Receive_SERVER_MAP_BEGIN(): frame_counter={}", _frame_counter);
807
810
811 Debug(net, 9, "Client::join_status = Downloading");
814
816}
817
830
832{
834 if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
835
836 /* We are still receiving data, put it to the file */
837 this->savegame->AddPacket(p);
838
839 _network_join_bytes = static_cast<uint32_t>(this->savegame->buffer.size());
841
843}
844
846{
848 if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
849
850 Debug(net, 9, "Client::Receive_SERVER_MAP_DONE()");
851
852 Debug(net, 9, "Client::join_status = Processing");
855
856 this->savegame->Reset();
857
858 /* The map is done downloading, load it */
860
861 /* Set the abstract filetype. This is read during savegame load. */
862 _file_to_saveload.SetMode(FIOS_TYPE_FILE, SLO_LOAD);
863
864 bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, this->savegame);
865 this->savegame = nullptr;
866
867 /* Long savegame loads shouldn't affect the lag calculation! */
868 this->last_packet = std::chrono::steady_clock::now();
869
870 if (!load_success) {
871 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SAVEGAMEERROR), {}, WL_CRITICAL);
873 }
874 /* If the savegame has successfully loaded, ALL windows have been removed,
875 * only toolbar/statusbar and gamefield are visible */
876
877 /* Say we received the map and loaded it correctly! */
878 SendMapOk();
879
880 /* As we skipped switch-mode, update the time we "switched". */
881 _game_session_stats.start_time = std::chrono::steady_clock::now();
882 _game_session_stats.savegame_size = std::nullopt;
883
884 ShowClientList();
885
886 /* New company/spectator (invalid company) or company we want to join is not active
887 * Switch local company to spectator and await the server's judgement */
890
891 if (_network_join.company != COMPANY_SPECTATOR) {
892 /* We have arrived and ready to start playing; send a command to make a new company;
893 * the server will give us a client-id and let us in */
894 Debug(net, 9, "Client::join_status = Registering");
896 ShowJoinStatusWindow();
897 Command<Commands::CompanyControl>::Post(CompanyCtrlAction::New, CompanyID::Invalid(), CompanyRemoveReason::None, _network_own_client_id);
898 }
899 } else {
900 /* take control over an existing company */
902 }
903
905
907}
908
910{
912
915#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
916 /* Test if the server supports this option
917 * and if we are at the frame the server is */
918#ifdef NETWORK_SEND_DOUBLE_SEED
919 if (p.CanReadFromPacket(sizeof(uint32_t) + sizeof(uint32_t))) {
920#else
921 if (p.CanReadFromPacket(sizeof(uint32_t))) {
922#endif
925#ifdef NETWORK_SEND_DOUBLE_SEED
926 _sync_seed_2 = p.Recv_uint32();
927#endif
928 }
929#endif
930 /* Receive the token. */
931 if (p.CanReadFromPacket(sizeof(uint8_t))) this->token = p.Recv_uint8();
932
933 /* Let the server know that we received this frame correctly
934 * We do this only once per day, to save some bandwidth ;) */
937 Debug(net, 7, "Sent ACK at {}", _frame_counter);
938 SendAck();
939 }
940
942}
943
945{
947
950#ifdef NETWORK_SEND_DOUBLE_SEED
951 _sync_seed_2 = p.Recv_uint32();
952#endif
953
954 Debug(net, 9, "Client::Receive_SERVER_SYNC(): sync_frame={}, sync_seed_1={}", _sync_frame, _sync_seed_1);
955
957}
958
960{
962
963 CommandPacket cp;
964 auto err = this->ReceiveCommand(p, cp);
965 cp.frame = p.Recv_uint32();
966 cp.my_cmd = p.Recv_bool();
967
968 Debug(net, 9, "Client::Receive_SERVER_COMMAND(): cmd={}, frame={}", cp.cmd, cp.frame);
969
970 if (err.has_value()) {
971 IConsolePrint(CC_WARNING, "Dropping server connection due to {}.", *err);
973 }
974
975 this->incoming_queue.push_back(std::move(cp));
976
978}
979
981{
983
984 std::string name;
985 const NetworkClientInfo *ci = nullptr, *ci_to;
986
989 bool self_send = p.Recv_bool();
990 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
991 int64_t data = p.Recv_uint64();
992
993 Debug(net, 9, "Client::Receive_SERVER_CHAT(): action={}, client_id={}, self_send={}", action, client_id, self_send);
994
996 if (ci_to == nullptr) return NETWORK_RECV_STATUS_OKAY;
997
998 /* Did we initiate the action locally? */
999 if (self_send) {
1000 switch (action) {
1001 case NETWORK_ACTION_CHAT_CLIENT:
1002 /* For speaking to client we need the client-name */
1003 name = ci_to->client_name;
1005 break;
1006
1007 /* For speaking to company, we need the company-name */
1008 case NETWORK_ACTION_CHAT_COMPANY: {
1009 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1010
1011 name = GetString(str, ci_to->client_playas);
1013 break;
1014 }
1015
1017 }
1018 } else {
1019 /* Display message from somebody else */
1020 name = ci_to->client_name;
1021 ci = ci_to;
1022 }
1023
1024 if (ci != nullptr) {
1025 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data);
1026 }
1028}
1029
1031{
1033
1034 std::string source = p.Recv_string(NETWORK_CHAT_LENGTH);
1035 TextColour colour = (TextColour)p.Recv_uint16();
1036 std::string user = p.Recv_string(NETWORK_CHAT_LENGTH);
1037 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1038
1039 Debug(net, 9, "Client::Receive_SERVER_EXTERNAL_CHAT(): source={}", source);
1040
1042
1043 NetworkTextMessage(NETWORK_ACTION_EXTERNAL_CHAT, colour, false, user, msg, source);
1044
1046}
1047
1049{
1051
1053
1054 Debug(net, 9, "Client::Receive_SERVER_ERROR_QUIT(): client_id={}", client_id);
1055
1057 if (ci != nullptr) {
1058 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", GetNetworkErrorMsg(static_cast<NetworkErrorCode>(p.Recv_uint8())));
1059 delete ci;
1060 }
1061
1063
1065}
1066
1068{
1070
1072
1073 Debug(net, 9, "Client::Receive_SERVER_QUIT(): client_id={}", client_id);
1074
1076 if (ci != nullptr) {
1077 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1078 delete ci;
1079 } else {
1080 Debug(net, 1, "Unknown client ({}) is leaving the game", client_id);
1081 }
1082
1084
1085 /* If we come here it means we could not locate the client.. strange :s */
1087}
1088
1090{
1092
1094
1095 Debug(net, 9, "Client::Receive_SERVER_JOIN(): client_id={}", client_id);
1096
1098 if (ci != nullptr) {
1099 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name);
1100 }
1101
1103
1105}
1106
1108{
1109 Debug(net, 9, "Client::Receive_SERVER_SHUTDOWN()");
1110
1111 /* Only when we're trying to join we really
1112 * care about the server shutting down. */
1113 if (this->status >= STATUS_JOIN) {
1114 ShowErrorMessage(GetEncodedString(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN), {}, WL_CRITICAL);
1115 }
1116
1118
1120}
1121
1123{
1124 Debug(net, 9, "Client::Receive_SERVER_NEWGAME()");
1125
1126 /* Only when we're trying to join we really
1127 * care about the server shutting down. */
1128 if (this->status >= STATUS_JOIN) {
1129 /* To throttle the reconnects a bit, every clients waits its
1130 * Client ID modulo 16 + 1 (value 0 means no reconnect).
1131 * This way reconnects should be spread out a bit. */
1133 ShowErrorMessage(GetEncodedString(STR_NETWORK_MESSAGE_SERVER_REBOOT), {}, WL_CRITICAL);
1134 }
1135
1137
1139}
1140
1142{
1144
1145 Debug(net, 9, "Client::Receive_SERVER_RCON()");
1146
1147 TextColour colour_code = (TextColour)p.Recv_uint16();
1149
1150 std::string rcon_out = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1151
1152 IConsolePrint(colour_code, rcon_out);
1153
1155}
1156
1158{
1160
1161 /* Nothing more in this packet... */
1163 CompanyID company_id = (CompanyID)p.Recv_uint8();
1164
1165 Debug(net, 9, "Client::Receive_SERVER_MOVE(): client_id={}, company_id={}", client_id, company_id);
1166
1167 if (client_id == 0) {
1168 /* definitely an invalid client id, debug message and do nothing. */
1169 Debug(net, 1, "Received invalid client index = 0");
1171 }
1172
1174 /* Just make sure we do not try to use a client_index that does not exist */
1175 if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY;
1176
1177 /* if not valid player, force spectator, else check player exists */
1178 if (!Company::IsValidID(company_id)) company_id = COMPANY_SPECTATOR;
1179
1181 SetLocalCompany(company_id);
1182 }
1183
1185}
1186
1200
1205{
1206 /* Only once we're authorized we can expect a steady stream of packets. */
1207 if (this->status < STATUS_AUTHORIZED) return;
1208
1209 /* 5 seconds are roughly twice the server's "you're slow" threshold (1 game day). */
1210 std::chrono::steady_clock::duration lag = std::chrono::steady_clock::now() - this->last_packet;
1211 if (lag < std::chrono::seconds(5)) return;
1212
1213 /* 20 seconds are (way) more than 4 game days after which
1214 * the server will forcefully disconnect you. */
1215 if (lag > std::chrono::seconds(20)) {
1217 return;
1218 }
1219
1220 /* Prevent showing the lag message every tick; just update it when needed. */
1221 static std::chrono::steady_clock::duration last_lag = {};
1222 if (std::chrono::duration_cast<std::chrono::seconds>(last_lag) == std::chrono::duration_cast<std::chrono::seconds>(lag)) return;
1223
1224 last_lag = lag;
1226 GetEncodedString(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION),
1227 GetEncodedString(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION, std::chrono::duration_cast<std::chrono::seconds>(lag).count()),
1228 WL_INFO);
1229}
1230
1231
1234{
1235 /* Set the frame-counter to 0 so nothing happens till we are ready */
1236 _frame_counter = 0;
1238 last_ack_frame = 0;
1239
1240 Debug(net, 9, "Client::NetworkClient_Connected()");
1241
1242 /* Request the game-info */
1244}
1245
1251void NetworkClientSendRcon(std::string_view password, std::string_view command)
1252{
1253 MyClient::SendRCon(password, command);
1254}
1255
1260void NetworkClientRequestMove(CompanyID company_id)
1261{
1262 MyClient::SendMove(company_id);
1263}
1264
1270{
1272 /* If our company is changing owner, go to spectators */
1274
1276 if (ci->client_playas != cid) continue;
1277 NetworkTextMessage(NETWORK_ACTION_COMPANY_SPECTATOR, CC_DEFAULT, false, ci->client_name);
1278 ci->client_playas = COMPANY_SPECTATOR;
1279 }
1280
1281 cur_company.Restore();
1282}
1283
1291bool NetworkIsValidClientName(std::string_view client_name)
1292{
1293 if (client_name.empty()) return false;
1294 if (client_name[0] == ' ') return false;
1295 return true;
1296}
1297
1313bool NetworkValidateClientName(std::string &client_name)
1314{
1315 StrTrimInPlace(client_name);
1316 if (NetworkIsValidClientName(client_name)) return true;
1317
1318 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_BAD_PLAYER_NAME), {}, WL_ERROR);
1319 return false;
1320}
1321
1330{
1331 return NetworkValidateClientName(_settings_client.network.client_name);
1332}
1333
1338void NetworkUpdateClientName(const std::string &client_name)
1339{
1341 if (ci == nullptr) return;
1342
1343 /* Don't change the name if it is the same as the old name */
1344 if (client_name == ci->client_name) return;
1345
1346 if (!_network_server) {
1347 MyClient::SendSetName(client_name);
1348 } else {
1349 /* Copy to a temporary buffer so no #n gets added after our name in the settings when there are duplicate names. */
1350 std::string temporary_name = client_name;
1351 if (NetworkMakeClientNameUnique(temporary_name)) {
1352 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, temporary_name);
1353 ci->client_name = std::move(temporary_name);
1355 }
1356 }
1357}
1358
1367void NetworkClientSendChat(NetworkAction action, DestType type, int dest, std::string_view msg, int64_t data)
1368{
1369 MyClient::SendChat(action, type, dest, msg, data);
1370}
1371
1378{
1379 /* Only companies actually playing can speak to team. Eg spectators cannot */
1380 if (!_settings_client.gui.prefer_teamchat || !Company::IsValidID(cio->client_playas)) return false;
1381
1382 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1383 if (ci->client_playas == cio->client_playas && ci != cio) return true;
1384 }
1385
1386 return false;
1387}
1388
1394{
1395 return _network_server ? _settings_client.network.max_companies : _network_server_max_companies;
1396}
1397
Class for backupping variables and making sure they are restored later.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
void SendResponse() override
Callback to trigger sending the response for the password request.
void AskUserForPassword(std::shared_ptr< NetworkAuthenticationPasswordRequest > request) override
Callback to trigger asking the user for the password.
NetworkRecvStatus Receive_SERVER_QUIT(Packet &p) override
Notification that a client left the game: uint32_t ID of the client.
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, std::string_view msg, int64_t data)
Send a chat-packet over the network.
static ClientNetworkGameSocketHandler * my_client
This is us!
static NetworkRecvStatus SendQuit()
Tell the server we would like to quit.
NetworkRecvStatus Receive_SERVER_SYNC(Packet &p) override
Sends a sync-check to the client: uint32_t Frame counter.
NetworkRecvStatus Receive_SERVER_ENABLE_ENCRYPTION(Packet &p) override
Indication to the client that authentication is complete and encryption has to be used from here on f...
NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet &p) override
Sends the size of the map to the client.
static bool Receive()
Check whether we received/can send some data from/to the server and when that's the case handle it ap...
NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet &p) override
Sends that all data of the map are sent to the client:
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override
Send information about a client: uint32_t ID of the client (always unique on a server.
std::string connection_string
Address we are connected to.
~ClientNetworkGameSocketHandler() override
Clear whatever we assigned.
static NetworkRecvStatus SendIdentify()
Identify ourselves to the server.
ServerStatus status
Status of the connection with the server.
NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet &p) override
Sends information about all used GRFs to the client: uint8_t Amount of GRFs (the following data is re...
static NetworkRecvStatus SendMove(CompanyID company)
Ask the server to move us.
NetworkRecvStatus Receive_SERVER_WAIT(Packet &p) override
Notification that another client is currently receiving the map: uint8_t Number of clients waiting in...
std::unique_ptr< class NetworkAuthenticationClientHandler > authentication_handler
The handler for the authentication.
std::shared_ptr< struct PacketReader > savegame
Packet reader for reading the savegame.
static bool IsConnected()
Check whether the client is actually connected (and in the game).
NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet &p) override
Sends a chat-packet for external source to the client: string Name of the source this message came fr...
uint8_t token
The token we need to send back to the server to prove we're the right client.
static NetworkRecvStatus SendSetName(const std::string &name)
Tell the server that we like to change the name of the client.
friend void NetworkExecuteLocalCommandQueue()
Execute all commands on the local command queue that ought to be executed this frame.
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet &p) override
Inform all clients that one client made an error and thus has quit/been disconnected: uint32_t ID of ...
static NetworkRecvStatus SendNewGRFsOk()
Tell the server we got all the NewGRFs.
static NetworkRecvStatus SendMapOk()
Tell the server we received the complete map.
void CheckConnection()
Check the connection's state, i.e.
ClientNetworkGameSocketHandler(SOCKET s, std::string_view connection_string)
Create a new socket for the client side of the game connection.
NetworkRecvStatus Receive_SERVER_RCON(Packet &p) override
Send the result of an issues RCon command back to the client: uint16_t Colour code.
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override
Notification that the client trying to join is banned.
NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet &p) override
Update the clients knowledge of the max settings: uint8_t Maximum number of companies allowed.
void ClientError(NetworkRecvStatus res)
Handle an error coming from the client side.
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override
The client is joined and ready to receive their map: uint32_t Own client ID.
static NetworkRecvStatus SendAck()
Send an acknowledgement from the server's ticks.
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet &p) override
Sends that the server will begin with sending the map to the client: uint32_t Current frame.
NetworkRecvStatus Receive_SERVER_JOIN(Packet &p) override
A client joined (PACKET_CLIENT_MAP_OK), what usually directly follows is a PACKET_SERVER_CLIENT_INFO:...
static NetworkRecvStatus SendAuthResponse()
Set the game password as requested.
static bool GameLoop()
Actual game loop for the client.
static void Send()
Send the packets of this socket handler.
@ STATUS_JOIN
We are trying to join a server.
@ STATUS_ENCRYPTED
The game authentication has completed and from here on the connection to the server is encrypted.
@ STATUS_MAP
The client is downloading the map.
@ STATUS_AUTH_GAME
Last action was requesting game (server) password.
@ STATUS_ACTIVE
The client is active within in the game.
@ STATUS_MAP_WAIT
The client is waiting as someone else is downloading the map.
@ STATUS_AUTHORIZED
The client is authorized at the server.
static NetworkRecvStatus SendRCon(std::string_view password, std::string_view command)
Send a console command.
NetworkRecvStatus Receive_SERVER_CHAT(Packet &p) override
Sends a chat-packet to the client: uint8_t ID of the action (see NetworkAction).
NetworkRecvStatus Receive_SERVER_MOVE(Packet &p) override
Move a client from one company into another: uint32_t ID of the client.
static NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the server.
NetworkRecvStatus Receive_SERVER_FRAME(Packet &p) override
Sends the current frame counter to the client: uint32_t Frame counter uint32_t Frame counter max (how...
NetworkRecvStatus Receive_SERVER_COMMAND(Packet &p) override
Sends a DoCommand to the client: uint8_t ID of the company (0..MAX_COMPANIES-1).
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet &p) override
Let the clients know that the server is loading a new map.
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override
Close the network connection due to the given status.
static NetworkRecvStatus SendGetMap()
Request the map from the server.
NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p) override
Indication to the client that it needs to authenticate: uint8_t The NetworkAuthenticationMethod to us...
NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet &p) override
Sends the data of the map to the client: Contains a part of the map (until max size of packet).
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override
The client made an error: uint8_t Error code caused (see NetworkErrorCode).
static NetworkRecvStatus SendError(NetworkErrorCode errorno)
Send an error-packet over the network.
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet &p) override
Let the clients know that the server is closing.
static NetworkRecvStatus SendJoin()
Tell the server we would like to join.
NetworkRecvStatus Receive_SERVER_FULL(Packet &p) override
Notification that the server is full.
@ AwaitUserInput
We have requested some user input, but must wait on that.
@ Invalid
We have received an invalid request.
@ ReadyForResponse
We do not have to wait for user input, and can immediately respond to the server.
static std::unique_ptr< NetworkAuthenticationClientHandler > Create(std::shared_ptr< NetworkAuthenticationPasswordRequestHandler > password_handler, std::string &secret_key, std::string &public_key)
Create a NetworkAuthenticationClientHandler.
Callback interface for client implementations to provide the handling of the password requests.
bool IsPendingDeletion() const
Is this pending for deletion and as such should not be accessed anymore.
Definition tcp_game.h:569
NetworkGameSocketHandler(SOCKET s)
Create a new socket for the game connection.
Definition tcp_game.cpp:28
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition tcp_game.h:555
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:525
CommandQueue incoming_queue
The command-queue awaiting handling.
Definition tcp_game.h:528
std::chrono::steady_clock::time_point last_packet
Time we received the last frame.
Definition tcp_game.h:529
void SetInfo(NetworkClientInfo *info)
Sets the client info for this socket handler.
Definition tcp_game.h:545
void DeferDeletion()
Mark this socket handler for deletion, once iterating the socket handlers is done.
Definition tcp_game.cpp:189
NetworkRecvStatus CloseConnection(bool error=true) override
Functions to help ReceivePacket/SendPacket a bit A socket can make errors.
Definition tcp_game.cpp:38
void MarkClosed()
Mark the connection as closed.
Definition core.h:64
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
SOCKET sock
The socket currently connected to.
Definition tcp.h:35
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition tcp.cpp:75
static void EventEnterMultiplayer(uint map_width, uint map_height)
Event: user entered a multiplayer game.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
Functions related to commands.
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...
CompanyID _current_company
Company currently doing an action.
Command definitions related to companies.
Functions related to companies.
GUI Functions related to companies.
@ New
Create a new company.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
@ None
Dummy reason for actions that don't need one.
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_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition config.h:51
static const uint NETWORK_PUBLIC_KEY_LENGTH
The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
Definition config.h:99
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition config.h:57
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.
bool IsValidConsoleColour(TextColour c)
Check whether the given TextColour is valid for console usage.
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_DESYNC
A desync did occur.
Definition core.h:23
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition core.h:26
@ NETWORK_RECV_STATUS_SERVER_ERROR
The server told us we made an error.
Definition core.h:28
@ NETWORK_RECV_STATUS_SAVEGAME
Something went wrong (down)loading the savegame.
Definition core.h:25
@ NETWORK_RECV_STATUS_CLOSE_QUERY
Done querying the server.
Definition core.h:31
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition core.h:22
@ NETWORK_RECV_STATUS_NEWGRF_MISMATCH
We did not have the required NewGRFs.
Definition core.h:24
@ NETWORK_RECV_STATUS_SERVER_FULL
The server is full.
Definition core.h:29
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition core.h:27
@ NETWORK_RECV_STATUS_SERVER_BANNED
The server has banned us.
Definition core.h:30
#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
Functions related to errors.
void ClearErrorMessages()
Clear all errors from the queue.
@ WL_ERROR
Errors (eg. saving/loading failed).
Definition error.h:26
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
SaveLoadOperation
Operation performed on the file.
Definition fileio_type.h:52
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:54
DetailedFileType
Kinds of files in each AbstractFileType.
Definition fileio_type.h:28
@ DFT_GAME_FILE
Save game or scenario file.
Definition fileio_type.h:31
Subdirectory
The different kinds of subdirectories OpenTTD uses.
Definition fileio_type.h:88
@ NO_DIRECTORY
A path without any base directory.
GameSessionStats _game_session_stats
Statistics about the current session.
Definition gfx.cpp:52
SwitchMode _switch_mode
The next mainloop command.
Definition gfx.cpp:50
Functions related to the gfx engine.
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
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve a short translateable string of the error code.
Definition network.cpp:312
uint32_t _frame_counter_server
The frame_counter of the server, if in network-mode.
Definition network.cpp:78
uint32_t _frame_counter
The current frame.
Definition network.cpp:80
uint8_t _network_reconnect
Reconnect timeout.
Definition network.cpp:74
bool _networking
are we in networking mode?
Definition network.cpp:67
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
uint32_t _sync_frame
The frame to perform the sync check.
Definition network.cpp:87
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:72
bool _network_first_time
Whether we have finished joining or not.
Definition network.cpp:88
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:79
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
void NetworkUpdateClientName(const std::string &client_name)
Send the server our name as callback from the setting.
NetworkJoinInfo _network_join
Information about the game to join to.
bool NetworkValidateOurClientName()
Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
void ClientNetworkEmergencySave()
Create an emergency savegame when the network connection is lost.
static uint32_t last_ack_frame
Last frame we performed an ack.
bool NetworkMaxCompaniesReached()
Check if max_companies has been reached on the server (local check only).
void NetworkClientSendRcon(std::string_view password, std::string_view command)
Send a remote console command.
uint NetworkMaxCompaniesAllowed()
Get the maximum number of companies that are allowed by the server.
void NetworkClientsToSpectators(CompanyID cid)
Move the clients of a company to the spectators.
static StringID GetLongNetworkErrorString(NetworkErrorCode error)
Get a long form translateable string for a NetworkErrorCode.
static uint8_t _network_server_max_companies
Maximum number of companies of the currently joined server.
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio)
Tell whether the client has team members who they can chat to.
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, std::string_view msg, int64_t data)
Send a chat message.
std::string _network_server_name
The current name of the server you are on.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
bool NetworkValidateClientName(std::string &client_name)
Trim the given client name in place, i.e.
bool NetworkIsValidClientName(std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
Client part of the network protocol.
NetworkJoinInfo _network_join
Information about the game to join to.
void NetworkClient_Connected()
Is called after a client is connected to the server.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
std::string_view GetNetworkRevisionString()
Get the network version string used by this build.
void DeserializeGRFIdentifier(Packet &p, GRFIdentifier &grf)
Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet.
Handling of the list of games.
NetworkJoinStatus _network_join_status
The status of joining.
uint8_t _network_join_waiting
The number of clients waiting in front of us.
uint32_t _network_join_bytes_total
The total number of bytes to download.
uint32_t _network_join_bytes
The number of bytes we already downloaded.
GUIs related to networking.
@ Waiting
Waiting for other clients to finish downloading the map.
@ Processing
Loading the savegame.
@ Registering
Creating a new company.
@ Authorizing
Starting authorizing the client to join the game and optionally company.
@ Downloading
Downloading the map from the server.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
DestType
Destination of our chat messages.
NetworkErrorCode
The error codes we send around in the protocols.
@ WrongRevision
The client is using the wrong revision.
@ General
Fallback error code in case nothing matches.
@ Desync
Client tells that they desynced.
@ SavegameFailed
Client tells they could not load the savegame.
@ 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).
@ NoAuthenticationMethodAvailable
The client and server could not find a common authentication method.
@ CompanyMismatch
The client was impersonating another company.
@ NewGRFMismatch
Client does not have the right NewGRFs.
NetworkAction
Actions that can be used for NetworkTextMessage.
ClientID
'Unique' identifier to be given to clients
@ CLIENT_ID_SERVER
Servers always have this ID.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ FGCM_EXACT
Only find Grfs matching md5sum.
void StateGameLoop()
State controlling game loop.
Definition openttd.cpp:1208
GameMode
Mode which defines the state of the game.
Definition openttd.h:18
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
Randomizer _random
Random used in the game state calculations.
Pseudo random number generator.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
void DoAutoOrNetsave(FiosNumberedSaveName &counter)
Create an autosave or netsave.
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.
Declaration of filters used for saving and loading savegames.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Interface definitions for game to report/respond to social integration.
Definition of base types and functions in a cross-platform compatible way.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
void StrTrimInPlace(std::string &str)
Trim the spaces from given string in place, i.e.
Definition string.cpp:230
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
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.
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
Everything we need to know about a command to be able to execute it.
uint32_t frame
the frame in which this packet is executed
bool my_cmd
did the command originate from "me"
Commands cmd
command being executed.
A savegame name automatically numbered.
Definition fios.h:127
Information about GRF, used in the game and (part of it) in savegames.
Basic data to distinguish a GRF.
uint32_t grfid
GRF ID (defined by Action 0x08).
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF).
LoadFilter(std::shared_ptr< LoadFilter > chain)
Initialise this filter.
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:262
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:271
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
CompanyID client_playas
As which company is this client playing (CompanyID).
std::string client_name
Name of the client.
std::string public_key
The public key of the client.
Information required to join a server.
size_t Read(uint8_t *rbuf, size_t size) override
Read a given number of bytes from the savegame.
std::deque< uint8_t > Buffer
The underlying buffer type that's being use.
PacketReader()
Initialise everything.
size_t read_bytes
The total number of read bytes.
void AddPacket(Packet &p)
Add a packet to this buffer.
Buffer::const_iterator iterator
Buffer we're going to write to/read from.
void Reset() override
Reset this filter to read from the beginning of the file.
Buffer buffer
Buffer with the raw save game data.
Internal entity of a packet.
Definition packet.h:47
uint16_t Recv_uint16()
Read a 16 bits integer from the packet.
Definition packet.cpp:330
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition packet.cpp:362
bool Recv_bool()
Read a boolean from the packet.
Definition packet.cpp:307
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
bool CanReadFromPacket(size_t bytes_to_read, bool close_connection=false)
Is it safe to read from the packet, i.e.
Definition packet.cpp:217
ssize_t TransferOut(F transfer_function)
Transfer data from the packet to the given function.
Definition packet.h:145
static Pool::IterateWrapper< NetworkClientInfo > Iterate(size_t from=0)
@ PACKET_CLIENT_IDENTIFY
Client telling the server the client's name and requested company.
Definition tcp_game.h:65
@ PACKET_CLIENT_GETMAP
Client requests the actual map.
Definition tcp_game.h:76
@ PACKET_CLIENT_ERROR
A client reports an error to the server.
Definition tcp_game.h:121
@ PACKET_CLIENT_JOIN
The client telling the server it wants to join.
Definition tcp_game.h:34
@ PACKET_CLIENT_AUTH_RESPONSE
The client responds to the authentication request.
Definition tcp_game.h:61
@ PACKET_CLIENT_NEWGRFS_CHECKED
Client acknowledges that it has all required NewGRFs.
Definition tcp_game.h:69
@ PACKET_CLIENT_COMMAND
Client executed a command and sends it to the server.
Definition tcp_game.h:98
@ PACKET_CLIENT_SET_NAME
A client changes its name.
Definition tcp_game.h:115
@ PACKET_CLIENT_ACK
The client tells the server which frame it has executed.
Definition tcp_game.h:94
@ PACKET_CLIENT_RCON
Client asks the server to execute some command.
Definition tcp_game.h:107
@ PACKET_CLIENT_MAP_OK
Client tells the server that it received the whole map.
Definition tcp_game.h:82
@ PACKET_CLIENT_QUIT
A client tells the server it is going to quit.
Definition tcp_game.h:119
@ PACKET_CLIENT_MOVE
A client would like to be moved to another company.
Definition tcp_game.h:111
@ PACKET_CLIENT_CHAT
Client said something that should be distributed.
Definition tcp_game.h:102
Base of all threads.
void CSleep(int milliseconds)
Sleep on the current thread for a defined time.
Definition thread.h:24
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1209
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:3321
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3199
Window functions not directly related to making/drawing windows.
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:44
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: