OpenTTD Source 20260421-master-gc2fbc6fdeb
network.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
12#include "../strings_func.h"
13#include "../command_func.h"
16#include "network_admin.h"
17#include "network_client.h"
18#include "network_query.h"
19#include "network_server.h"
20#include "network_content.h"
21#include "network_udp.h"
22#include "network_gamelist.h"
23#include "network_base.h"
24#include "network_coordinator.h"
25#include "core/udp.h"
26#include "core/host.h"
27#include "network_gui.h"
28#include "../console_func.h"
29#include "../3rdparty/md5/md5.h"
31#include "../window_func.h"
32#include "../company_func.h"
33#include "../company_base.h"
34#include "../landscape_type.h"
35#include "../rev.h"
36#include "../core/pool_func.hpp"
37#include "../gfx_func.h"
38#include "../error.h"
39#include "../misc_cmd.h"
41#ifdef DEBUG_DUMP_COMMANDS
42# include "../fileio_func.h"
44#endif
45#include <charconv>
46
47#include "table/strings.h"
48
49#include "../safeguards.h"
50
51#ifdef DEBUG_DUMP_COMMANDS
57bool _ddc_fastforward = true;
58#endif /* DEBUG_DUMP_COMMANDS */
59
62
66
83uint32_t _sync_seed_1;
84#ifdef NETWORK_SEND_DOUBLE_SEED
85uint32_t _sync_seed_2;
86#endif
87uint32_t _sync_frame;
89
92
93extern std::string GenerateUid(std::string_view subject);
94
100{
101 return !NetworkClientSocket::Iterate().empty();
102}
103
108{
109 /* Delete the chat window, if you were chatting with this client. */
111}
112
119{
121 if (ci->client_id == client_id) return ci;
122 }
123
124 return nullptr;
125}
126
132bool NetworkClientInfo::CanJoinCompany(CompanyID company_id) const
133{
134 Company *c = Company::GetIfValid(company_id);
135 return c != nullptr && (c->allow_any || c->allow_list.Contains(this->public_key));
136}
137
143bool NetworkCanJoinCompany(CompanyID company_id)
144{
146 return info != nullptr && info->CanJoinCompany(company_id);
147}
148
155{
157 if (cs->client_id == client_id) return cs;
158 }
159
160 return nullptr;
161}
162
163
170static auto FindKey(auto *authorized_keys, std::string_view authorized_key)
171{
172 return std::ranges::find_if(*authorized_keys, [authorized_key](auto &value) { return StrEqualsIgnoreCase(value, authorized_key); });
173}
174
180bool NetworkAuthorizedKeys::Contains(std::string_view key) const
181{
182 return FindKey(this, key) != this->end();
183}
184
190bool NetworkAuthorizedKeys::Add(std::string_view key)
191{
192 if (key.empty()) return false;
193
194 auto iter = FindKey(this, key);
195 if (iter != this->end()) return false;
196
197 this->emplace_back(key);
198 return true;
199}
200
206bool NetworkAuthorizedKeys::Remove(std::string_view key)
207{
208 auto iter = FindKey(this, key);
209 if (iter == this->end()) return false;
210
211 this->erase(iter);
212 return true;
213}
214
215
221{
222 uint8_t count = 0;
223
225 if (ci->client_playas == COMPANY_SPECTATOR) count++;
226 }
227
228 /* Don't count a dedicated server as spectator */
229 if (_network_dedicated) count--;
230
231 return count;
232}
233
234
244void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, std::string_view name, std::string_view str, StringParameter &&data)
245{
246 std::string message;
247 StringBuilder builder(message);
248
249 /* All of these strings start with "***". These characters are interpreted as both left-to-right and
250 * right-to-left characters depending on the context. As the next text might be an user's name, the
251 * user name's characters will influence the direction of the "***" instead of the language setting
252 * of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
254
255 switch (action) {
257 /* Ignore invalid messages */
258 builder += GetString(STR_NETWORK_SERVER_MESSAGE, str);
259 colour = CC_DEFAULT;
260 break;
262 colour = CC_DEFAULT;
263 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE, name);
264 break;
266 colour = CC_DEFAULT;
267 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN, name, str);
268 break;
270 colour = CC_DEFAULT;
271 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW, name, std::move(data));
272 break;
274 /* Show the Client ID for the server but not for the client. */
275 builder += _network_server ?
276 GetString(STR_NETWORK_MESSAGE_CLIENT_JOINED_ID, name, std::move(data)) :
277 GetString(STR_NETWORK_MESSAGE_CLIENT_JOINED, name);
278 break;
279 case NetworkAction::ClientLeave: builder += GetString(STR_NETWORK_MESSAGE_CLIENT_LEFT, name, std::move(data)); break;
280 case NetworkAction::ClientNameChange:builder += GetString(STR_NETWORK_MESSAGE_NAME_CHANGE, name, str); break;
281 case NetworkAction::GiveMoney: builder += GetString(STR_NETWORK_MESSAGE_GIVE_MONEY, name, std::move(data), str); break;
282 case NetworkAction::ClientKicked: builder += GetString(STR_NETWORK_MESSAGE_KICKED, name, str); break;
283 case NetworkAction::ChatTeam: builder += GetString(self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, name, str); break;
284 case NetworkAction::ChatClient: builder += GetString(self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, name, str); break;
285 case NetworkAction::ChatExternal: builder += GetString(STR_NETWORK_CHAT_EXTERNAL, std::move(data), name, str); break;
286 default: builder += GetString(STR_NETWORK_CHAT_ALL, name, str); break;
287 }
288
289 Debug(desync, 1, "msg: {:08x}; {:02x}; {}", TimerGameEconomy::date, TimerGameEconomy::date_fract, message);
290 IConsolePrint(colour, message);
291 NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
292}
293
300{
301 int lag = cs->last_frame_server - cs->last_frame;
302 /* This client has missed their ACK packet after 1 DAY_TICKS..
303 * so we increase their lag for every frame that passes!
304 * The packet can be out by a max of _net_frame_freq */
305 if (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) {
306 lag += _frame_counter - (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq);
307 }
308 return lag;
309}
310
311
316void ShowNetworkError(StringID error_string)
317{
320}
321
329{
330 switch (err) {
331 default:
332 case NetworkErrorCode::General: return STR_NETWORK_ERROR_CLIENT_GENERAL;
333 case NetworkErrorCode::Desync: return STR_NETWORK_ERROR_CLIENT_DESYNC;
334 case NetworkErrorCode::SavegameFailed: return STR_NETWORK_ERROR_CLIENT_SAVEGAME;
335 case NetworkErrorCode::ConnectionLost: return STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST;
336 case NetworkErrorCode::IllegalPacket: return STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR;
337 case NetworkErrorCode::NewGRFMismatch: return STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH;
338 case NetworkErrorCode::NotAuthorized: return STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED;
339 case NetworkErrorCode::NotExpected: return STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED;
340 case NetworkErrorCode::WrongRevision: return STR_NETWORK_ERROR_CLIENT_WRONG_REVISION;
341 case NetworkErrorCode::NameInUse: return STR_NETWORK_ERROR_CLIENT_NAME_IN_USE;
342 case NetworkErrorCode::WrongPassword: return STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD;
343 case NetworkErrorCode::CompanyMismatch: return STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH;
344 case NetworkErrorCode::Kicked: return STR_NETWORK_ERROR_CLIENT_KICKED;
345 case NetworkErrorCode::Cheater: return STR_NETWORK_ERROR_CLIENT_CHEATER;
346 case NetworkErrorCode::ServerFull: return STR_NETWORK_ERROR_CLIENT_SERVER_FULL;
347 case NetworkErrorCode::TooManyCommands: return STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS;
348 case NetworkErrorCode::TimeoutPassword: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD;
349 case NetworkErrorCode::TimeoutComputer: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER;
350 case NetworkErrorCode::TimeoutMap: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP;
351 case NetworkErrorCode::TimeoutJoin: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN;
352 case NetworkErrorCode::InvalidClientName: return STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME;
353 case NetworkErrorCode::NotOnAllowList: return STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST;
354 case NetworkErrorCode::NoAuthenticationMethodAvailable: return STR_NETWORK_ERROR_CLIENT_NO_AUTHENTICATION_METHOD_AVAILABLE;
355 };
356}
357
363void NetworkHandlePauseChange(PauseModes prev_mode, PauseMode changed_mode)
364{
365 if (!_networking) return;
366
367 switch (changed_mode) {
369 case PauseMode::Join:
373 bool changed = _pause_mode.None() != prev_mode.None();
374 bool paused = _pause_mode.Any();
375 if (!paused && !changed) return;
376
377 std::string str;
378 if (!changed) {
379 std::array<StringParameter, 5> params{};
380 auto it = params.begin();
381 if (_pause_mode.Test(PauseMode::Normal)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL;
382 if (_pause_mode.Test(PauseMode::Join)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS;
383 if (_pause_mode.Test(PauseMode::GameScript)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT;
384 if (_pause_mode.Test(PauseMode::ActiveClients)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS;
385 if (_pause_mode.Test(PauseMode::LinkGraph)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH;
386 str = GetStringWithArgs(STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + std::distance(params.begin(), it) - 1, {params.begin(), it});
387 } else {
388 StringID reason;
389 switch (changed_mode) {
390 case PauseMode::Normal: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL; break;
391 case PauseMode::Join: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS; break;
392 case PauseMode::GameScript: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT; break;
393 case PauseMode::ActiveClients: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS; break;
394 case PauseMode::LinkGraph: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH; break;
395 default: NOT_REACHED();
396 }
397 str = GetString(paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED, reason);
398 }
399
401 break;
402 }
403
404 default:
405 return;
406 }
407}
408
409
418static void CheckPauseHelper(bool pause, PauseMode pm)
419{
420 if (pause == _pause_mode.Test(pm)) return;
421
422 Command<Commands::Pause>::Post(pm, pause);
423}
424
431{
432 uint count = 0;
433
434 for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
435 if (cs->status != NetworkClientSocket::STATUS_ACTIVE) continue;
436 if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue;
437 count++;
438 }
439
440 return count;
441}
442
447{
448 if (_pause_mode.Test(PauseMode::Error) ||
450 (_settings_client.network.min_active_clients == 0 && !_pause_mode.Test(PauseMode::ActiveClients))) {
451 return;
452 }
454}
455
461{
462 for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
463 if (cs->status >= NetworkClientSocket::STATUS_AUTHORIZED && cs->status < NetworkClientSocket::STATUS_ACTIVE) return true;
464 }
465
466 return false;
467}
468
472static void CheckPauseOnJoin()
473{
474 if (_pause_mode.Test(PauseMode::Error) ||
475 (!_settings_client.network.pause_on_join && !_pause_mode.Test(PauseMode::Join))) {
476 return;
477 }
479}
480
487std::string_view ParseCompanyFromConnectionString(std::string_view connection_string, CompanyID *company_id)
488{
489 std::string_view ip = connection_string;
490 if (company_id == nullptr) return ip;
491
492 size_t offset = ip.find_last_of('#');
493 if (offset != std::string::npos) {
494 std::string_view company_string = ip.substr(offset + 1);
495 ip = ip.substr(0, offset);
496
497 uint8_t company_value;
498 auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
499 if (err == std::errc()) {
500 if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
501 if (company_value > MAX_COMPANIES || company_value == 0) {
502 *company_id = COMPANY_SPECTATOR;
503 } else {
504 /* "#1" means the first company, which has index 0. */
505 *company_id = (CompanyID)(company_value - 1);
506 }
507 } else {
508 *company_id = (CompanyID)company_value;
509 }
510 }
511 }
512
513 return ip;
514}
515
531std::string_view ParseFullConnectionString(std::string_view connection_string, uint16_t &port, CompanyID *company_id)
532{
533 std::string_view ip = ParseCompanyFromConnectionString(connection_string, company_id);
534
535 size_t port_offset = ip.find_last_of(':');
536 size_t ipv6_close = ip.find_last_of(']');
537 if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) {
538 std::string_view port_string = ip.substr(port_offset + 1);
539 ip = ip.substr(0, port_offset);
540 std::from_chars(port_string.data(), port_string.data() + port_string.size(), port);
541 }
542 return ip;
543}
544
551std::string NormalizeConnectionString(std::string_view connection_string, uint16_t default_port)
552{
553 uint16_t port = default_port;
554 std::string_view ip = ParseFullConnectionString(connection_string, port);
555 return fmt::format("{}:{}", ip, port);
556}
557
566NetworkAddress ParseConnectionString(std::string_view connection_string, uint16_t default_port)
567{
568 uint16_t port = default_port;
569 std::string_view ip = ParseFullConnectionString(connection_string, port);
570 return NetworkAddress(ip, port);
571}
572
578/* static */ void ServerNetworkGameSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address)
579{
580 /* Register the login */
582
584 cs->client_address = address; // Save the IP of the client
585
587}
588
593static void InitializeNetworkPools(bool close_admins = true)
594{
595 PoolTypes to_clean{PoolType::NetworkClient};
596 if (close_admins) to_clean.Set(PoolType::NetworkAdmin);
597 PoolBase::Clean(to_clean);
598}
599
604void NetworkClose(bool close_admins)
605{
606 if (_network_server) {
607 if (close_admins) {
609 as->CloseConnection(true);
610 }
611 }
612
613 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
614 cs->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
615 }
618
619 _network_coordinator_client.CloseConnection();
620 } else {
621 if (MyClient::my_client != nullptr) {
624 }
625
626 _network_coordinator_client.CloseAllConnections();
627 }
629
631
632 _networking = false;
633 _network_server = false;
634
636
637 InitializeNetworkPools(close_admins);
638}
639
644static void NetworkInitialize(bool close_admins = true)
645{
646 InitializeNetworkPools(close_admins);
647
648 _sync_frame = 0;
649 _network_first_time = true;
650
652}
653
656private:
657 std::string connection_string;
658
659public:
665
666 void OnFailure() override
667 {
668 Debug(net, 9, "Query::OnFailure(): connection_string={}", this->connection_string);
669
671 item->status = NGLS_OFFLINE;
672 item->refreshing = false;
673
675 }
676
677 void OnConnect(SOCKET s) override
678 {
679 Debug(net, 9, "Query::OnConnect(): connection_string={}", this->connection_string);
680
681 QueryNetworkGameSocketHandler::QueryServer(s, this->connection_string);
682 }
683};
684
689void NetworkQueryServer(std::string_view connection_string)
690{
691 if (!_network_available) return;
692
693 Debug(net, 9, "NetworkQueryServer(): connection_string={}", connection_string);
694
695 /* Mark the entry as refreshing, so the GUI can show the refresh is pending. */
696 NetworkGame *item = NetworkGameListAddItem(connection_string);
697 item->refreshing = true;
698
700}
701
711NetworkGame *NetworkAddServer(std::string_view connection_string, bool manually, bool never_expire)
712{
713 if (connection_string.empty()) return nullptr;
714
715 /* Ensure the item already exists in the list */
716 NetworkGame *item = NetworkGameListAddItem(connection_string);
717 if (item->info.server_name.empty()) {
719 item->info.server_name = connection_string;
720
722
723 NetworkQueryServer(connection_string);
724 }
725
726 if (manually) item->manually = true;
727 if (never_expire) item->version = INT32_MAX;
728
729 return item;
730}
731
737void GetBindAddresses(NetworkAddressList *addresses, uint16_t port)
738{
739 for (const auto &iter : _network_bind_list) {
740 addresses->emplace_back(iter, port);
741 }
742
743 /* No address, so bind to everything. */
744 if (addresses->empty()) {
745 addresses->emplace_back("", port);
746 }
747}
748
754{
755 _network_host_list.clear();
756
757 for (const auto &item : _network_game_list) {
758 if (item->manually) _network_host_list.emplace_back(item->connection_string);
759 }
760}
761
764private:
765 std::string connection_string;
766
767public:
773
774 void OnFailure() override
775 {
776 Debug(net, 9, "Client::OnFailure(): connection_string={}", this->connection_string);
777
778 ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION);
779 }
780
781 void OnConnect(SOCKET s) override
782 {
783 Debug(net, 9, "Client::OnConnect(): connection_string={}", this->connection_string);
784
785 _networking = true;
787 new ClientNetworkGameSocketHandler(s, this->connection_string);
788 IConsoleCmdExec("exec scripts/on_client.scr 0");
790 }
791};
792
809bool NetworkClientConnectGame(std::string_view connection_string, CompanyID default_company, const std::string &join_server_password)
810{
811 Debug(net, 9, "NetworkClientConnectGame(): connection_string={}", connection_string);
812
813 CompanyID join_as = default_company;
814 std::string resolved_connection_string = ServerAddress::Parse(connection_string, NETWORK_DEFAULT_PORT, &join_as).connection_string;
815
816 if (!_network_available) return false;
817 if (!NetworkValidateOurClientName()) return false;
818
819 _network_join.connection_string = std::move(resolved_connection_string);
820 _network_join.company = join_as;
821 _network_join.server_password = join_server_password;
822
823 if (_game_mode == GM_MENU) {
824 /* From the menu we can immediately continue with the actual join. */
826 } else {
827 /* When already playing a game, first go back to the main menu. This
828 * disconnects the user from the current game, meaning we can safely
829 * load in the new. After all, there is little point in continuing to
830 * play on a server if we are connecting to another one.
831 */
833 }
834 return true;
835}
836
843{
846
847 _settings_client.network.last_joined = _network_join.connection_string;
848 Debug(net, 9, "status = Connecting");
851
853}
854
857{
859 /* The server is a client too */
860 _network_game_info.clients_on = _network_dedicated ? 0 : 1;
861}
862
865{
866 /* There should be always space for the server. */
870
871 ci->client_name = _settings_client.network.client_name;
872
874 ci->public_key = _settings_client.network.client_public_key;
875}
876
887bool NetworkValidateServerName(std::string &server_name)
888{
889 StrTrimInPlace(server_name);
890 if (!server_name.empty()) return true;
891
892 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_BAD_SERVER_NAME), {}, WL_ERROR);
893 return false;
894}
895
903{
904 static const std::string fallback_client_name = "Unnamed Client";
905 StrTrimInPlace(_settings_client.network.client_name);
906 if (_settings_client.network.client_name.empty() || _settings_client.network.client_name == fallback_client_name) {
907 Debug(net, 1, "No \"client_name\" has been set, using \"{}\" instead. Please set this now using the \"name <new name>\" command", fallback_client_name);
908 _settings_client.network.client_name = fallback_client_name;
909 }
910
911 static const std::string fallback_server_name = "Unnamed Server";
912 StrTrimInPlace(_settings_client.network.server_name);
913 if (_settings_client.network.server_name.empty() || _settings_client.network.server_name == fallback_server_name) {
914 Debug(net, 1, "No \"server_name\" has been set, using \"{}\" instead. Please set this now using the \"server_name <new name>\" command", fallback_server_name);
915 _settings_client.network.server_name = fallback_server_name;
916 }
917}
918
924{
925 if (!_network_available) return false;
926
927 /* Call the pre-scripts */
928 IConsoleCmdExec("exec scripts/pre_server.scr 0");
929 if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
930
931 /* Check for the client and server names to be set, but only after the scripts had a chance to set them.*/
933
934 NetworkDisconnect(false);
935 NetworkInitialize(false);
937 Debug(net, 5, "Starting listeners for clients");
938 if (!ServerNetworkGameSocketHandler::Listen(_settings_client.network.server_port)) return false;
939
940 /* Only listen for admins when the authentication is configured. */
941 if (_settings_client.network.AdminAuthenticationConfigured()) {
942 Debug(net, 5, "Starting listeners for admins");
943 if (!ServerNetworkAdminSocketHandler::Listen(_settings_client.network.server_admin_port)) return false;
944 }
945
946 /* Try to start UDP-server */
947 Debug(net, 5, "Starting listeners for incoming server queries");
949
950 _network_server = true;
951 _networking = true;
952 _frame_counter = 0;
957
959
962
963 if (_settings_client.network.server_game_type != ServerGameType::Local) {
965 }
966
967 /* execute server initialization script */
968 IConsoleCmdExec("exec scripts/on_server.scr 0");
969 /* if the server is dedicated ... add some other script */
970 if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
971
972 return true;
973}
974
980{
981 if (!_network_server) return;
982
983 /* Update the static game info to set the values from the new game. */
985
987
988 if (!_network_dedicated) {
991 if (c != nullptr && ci != nullptr) {
992 ci->client_playas = c->index;
993
994 /*
995 * If the company has not been named yet, the company was just started.
996 * Otherwise it would have gotten a name already, so announce it as a new company.
997 */
998 if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) NetworkServerNewCompany(c, ci);
999 }
1000
1002 } else {
1003 /* welcome possibly still connected admins - this can only happen on a dedicated server. */
1005 }
1006}
1007
1013{
1014 if (_network_server) {
1015 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1016 cs->SendNewGame();
1017 cs->SendPackets();
1018 }
1019
1021 as->SendNewGame();
1022 as->SendPackets();
1023 }
1024 }
1025
1026 /* For non-dedicated servers we have to kick the admins as we are not
1027 * certain that we will end up in a new network game. */
1029}
1030
1035void NetworkDisconnect(bool close_admins)
1036{
1037 if (_network_server) {
1038 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1039 cs->SendShutdown();
1040 cs->SendPackets();
1041 }
1042
1043 if (close_admins) {
1045 as->SendShutdown();
1046 as->SendPackets();
1047 }
1048 }
1049 }
1050
1052
1053 NetworkClose(close_admins);
1054
1055 /* Reinitialize the UDP stack, i.e. close all existing connections. */
1057}
1058
1064{
1065 if (!_networking) return;
1066
1067 switch (_settings_client.network.server_game_type) {
1069 _network_coordinator_client.CloseConnection();
1070 break;
1071
1074 _network_coordinator_client.Register();
1075 break;
1076
1077 default:
1078 NOT_REACHED();
1079 }
1080}
1081
1086static bool NetworkReceive()
1087{
1088 bool result;
1089 if (_network_server) {
1092 } else {
1094 }
1096 return result;
1097}
1098
1110
1127
1133{
1134 if (!_networking) return;
1135
1136 if (!NetworkReceive()) return;
1137
1138 if (_network_server) {
1139 /* Log the sync state to check for in-syncedness of replays. */
1141 /* We don't want to log multiple times if paused. */
1142 static TimerGameEconomy::Date last_log;
1143 if (last_log != TimerGameEconomy::date) {
1144 Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _random.state[0], _random.state[1]);
1145 last_log = TimerGameEconomy::date;
1146 }
1147 }
1148
1149#ifdef DEBUG_DUMP_COMMANDS
1150 /* Loading of the debug commands from -ddesync>=1 */
1151 static auto f = FioFOpenFile("commands.log", "rb", Subdirectory::Save);
1152 static TimerGameEconomy::Date next_date(0);
1153 static uint32_t next_date_fract;
1154 static CommandPacket *cp = nullptr;
1155 static bool check_sync_state = false;
1156 static uint32_t sync_state[2];
1157 if (!f.has_value() && next_date == 0) {
1158 Debug(desync, 0, "Cannot open commands.log");
1159 next_date = TimerGameEconomy::Date(1);
1160 }
1161
1162 while (f.has_value() && !feof(*f)) {
1163 if (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract == next_date_fract) {
1164 if (cp != nullptr) {
1165 NetworkSendCommand(cp->cmd, cp->err_msg, nullptr, cp->company, cp->data);
1166 Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {} ({})", TimerGameEconomy::date, TimerGameEconomy::date_fract, _current_company.base(), cp->cmd, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
1167 delete cp;
1168 cp = nullptr;
1169 }
1170 if (check_sync_state) {
1171 if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
1172 Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", TimerGameEconomy::date, TimerGameEconomy::date_fract);
1173 } else {
1174 Debug(desync, 0, "Sync check: {:08x}; {:02x}; mismatch expected {{{:08x}, {:08x}}}, got {{{:08x}, {:08x}}}",
1175 TimerGameEconomy::date, TimerGameEconomy::date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
1176 NOT_REACHED();
1177 }
1178 check_sync_state = false;
1179 }
1180 }
1181
1182 /* Skip all entries in the command-log till we caught up with the current game again. */
1183 if (TimerGameEconomy::date > next_date || (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract > next_date_fract)) {
1184 Debug(desync, 0, "Skipping to next command at {:08x}:{:02x}", next_date, next_date_fract);
1185 if (cp != nullptr) {
1186 delete cp;
1187 cp = nullptr;
1188 }
1189 check_sync_state = false;
1190 }
1191
1192 if (cp != nullptr || check_sync_state) break;
1193
1194 char buff[4096];
1195 if (fgets(buff, lengthof(buff), *f) == nullptr) break;
1196
1197 StringConsumer consumer{std::string_view{buff}};
1198 /* Ignore the "[date time] " part of the message */
1199 if (consumer.ReadCharIf('[')) {
1201 consumer.SkipCharIf(' ');
1202 }
1203
1204 if (consumer.ReadIf("cmd: ")
1205#ifdef DEBUG_FAILED_DUMP_COMMANDS
1206 || consumer.ReadIf("cmdf: ")
1207#endif
1208 ) {
1209 cp = new CommandPacket();
1210 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1211 bool valid = consumer.ReadIf("; ");
1212 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1213 valid &= consumer.ReadIf("; ");
1214 cp->company = static_cast<CompanyID>(consumer.ReadIntegerBase<uint16_t>(16));
1215 valid &= consumer.ReadIf("; ");
1216 cp->cmd = static_cast<Commands>(consumer.ReadIntegerBase<uint32_t>(16));
1217 valid &= consumer.ReadIf("; ");
1218 cp->err_msg = consumer.ReadIntegerBase<uint32_t>(16);
1219 valid &= consumer.ReadIf("; ");
1220 auto args = consumer.ReadUntilChar(' ', StringConsumer::SKIP_ONE_SEPARATOR);
1221 assert(valid);
1222
1223 /* Parse command data. */
1224 cp->data.clear();
1225 for (size_t i = 0; i + 1 < args.size(); i += 2) {
1226 uint8_t e = 0;
1227 std::from_chars(args.data() + i, args.data() + i + 2, e, 16);
1228 cp->data.push_back(e);
1229 }
1230 } else if (consumer.ReadIf("join: ")) {
1231 /* Manually insert a pause when joining; this way the client can join at the exact right time. */
1232 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1233 bool valid = consumer.ReadIf("; ");
1234 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1235 assert(valid);
1236 Debug(desync, 0, "Injecting pause for join at {:08x}:{:02x}; please join when paused", next_date, next_date_fract);
1237 cp = new CommandPacket();
1239 cp->cmd = Commands::Pause;
1240 cp->data = EndianBufferWriter<>::FromValue(CommandTraits<Commands::Pause>::Args{ PauseMode::Normal, true });
1241 _ddc_fastforward = false;
1242 } else if (consumer.ReadIf("sync: ")) {
1243 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1244 bool valid = consumer.ReadIf("; ");
1245 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1246 valid &= consumer.ReadIf("; ");
1247 sync_state[0] = consumer.ReadIntegerBase<uint32_t>(16);
1248 valid &= consumer.ReadIf("; ");
1249 sync_state[1] = consumer.ReadIntegerBase<uint32_t>(16);
1250 assert(valid);
1251 check_sync_state = true;
1252 } else if (consumer.ReadIf("msg: ") || consumer.ReadIf("client: ") ||
1253 consumer.ReadIf("load: ") || consumer.ReadIf("save: ") ||
1254 consumer.ReadIf("warning: ")) {
1255 /* A message that is not very important to the log playback, but part of the log. */
1256#ifndef DEBUG_FAILED_DUMP_COMMANDS
1257 } else if (consumer.ReadIf("cmdf: ")) {
1258 Debug(desync, 0, "Skipping replay of failed command: {}", consumer.Read(StringConsumer::npos));
1259#endif
1260 } else {
1261 /* Can't parse a line; what's wrong here? */
1262 Debug(desync, 0, "Trying to parse: {}", consumer.Read(StringConsumer::npos));
1263 NOT_REACHED();
1264 }
1265 }
1266 if (f.has_value() && feof(*f)) {
1267 Debug(desync, 0, "End of commands.log");
1268 f.reset();
1269 }
1270#endif /* DEBUG_DUMP_COMMANDS */
1272 /* Only check for active clients just before we're going to send out
1273 * the commands so we don't send multiple pause/unpause commands when
1274 * the frame_freq is more than 1 tick. Same with distributing commands. */
1278 }
1279
1280 bool send_frame = false;
1281
1282 /* We first increase the _frame_counter */
1284 /* Update max-frame-counter */
1286 _frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
1287 send_frame = true;
1288 }
1289
1291
1292 /* Then we make the frame */
1293 StateGameLoop();
1294
1295 _sync_seed_1 = _random.state[0];
1296#ifdef NETWORK_SEND_DOUBLE_SEED
1297 _sync_seed_2 = _random.state[1];
1298#endif
1299
1300 NetworkServer_Tick(send_frame);
1301 } else {
1302 /* Client */
1303
1304 /* Make sure we are at the frame were the server is (quick-frames) */
1306 /* Run a number of frames; when things go bad, get out. */
1309 }
1310 } else {
1311 /* Else, keep on going till _frame_counter_max */
1313 /* Run one frame; if things went bad, get out. */
1315 }
1316 }
1317 }
1318
1319 NetworkSend();
1320}
1321
1324{
1325 Debug(net, 3, "Starting network");
1326
1327 /* Network is available */
1329 _network_dedicated = false;
1330
1331 _network_game_info = {};
1332
1335 Debug(net, 3, "Network online, multiplayer available");
1338}
1339
1342{
1346
1347 Debug(net, 3, "Shutting down network");
1348
1349 _network_available = false;
1350
1352}
1353
1354#ifdef __EMSCRIPTEN__
1355extern "C" {
1356
1357void CDECL em_openttd_add_server(const char *connection_string)
1358{
1359 NetworkAddServer(connection_string, false, true);
1360}
1361
1362}
1363#endif
std::vector< NetworkAddress > NetworkAddressList
Type for a list of addresses.
Definition address.h:20
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Set()
Set all bits.
void PutUtf8(char32_t c)
Append UTF-8 char.
Class for handling the client side of the game connection.
static ClientNetworkGameSocketHandler * my_client
This is us!
static NetworkRecvStatus SendQuit()
Tell the server we would like to quit.
static bool Receive()
Check whether we received/can send some data from/to the server and when that's the case handle it ap...
static bool GameLoop()
Actual game loop for the client.
static void Send()
Send the packets of this socket handler.
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
Definition address.h:28
static void EnsureValidSecretKeyAndUpdatePublicKey(std::string &secret_key, std::string &public_key)
Ensures that the given secret key is valid, and when not overwrite it with a valid secret key.
bool Contains(std::string_view key) const
Check whether the given key is contains in these authorized keys.
Definition network.cpp:180
bool Add(std::string_view key)
Add the given key to the authorized keys, when it is not already contained.
Definition network.cpp:190
bool Remove(std::string_view key)
Remove the given key from the authorized keys, when it is exists.
Definition network.cpp:206
static void ProcessDeferredDeletions()
Actually delete the socket handlers that were marked for deletion.
Definition tcp_game.cpp:196
ClientID client_id
Client identifier.
Definition tcp_game.h:527
static void HTTPReceive()
Do the receiving for all HTTP connections.
static void SendReceive()
Check if any query needs to send or receive.
static void QueryServer(SOCKET s, std::string_view connection_string)
Start to query a server based on an open socket.
std::string connection_string
The connection string for this ServerAddress.
Definition address.h:199
static ServerAddress Parse(std::string_view connection_string, uint16_t default_port, CompanyID *company_id=nullptr)
Convert a string containing either "hostname", "hostname:port" or invite code to a ServerAddress,...
Definition address.cpp:444
Class for handling the server side of the game connection.
static void Send()
Send the packets for the server sockets.
static void WelcomeAll()
Send a Welcome packet to all connected admins.
static Pool::IterateWrapperFiltered< ServerNetworkAdminSocketHandler, ServerNetworkAdminSocketHandlerFilter > IterateActive(size_t from=0)
Returns an iterable ensemble of all active admin sockets.
static ServerNetworkGameSocketHandler * GetByClientID(ClientID client_id)
Return the client state given it's client-identifier.
Definition network.cpp:154
static void Send()
Send the packets for the server sockets.
static void AcceptConnection(SOCKET s, const NetworkAddress &address)
Handle the accepting of a connection to the server.
Definition network.cpp:578
ServerNetworkGameSocketHandler(ClientPoolID index, SOCKET s)
Create a new socket for the server side of the game connection.
NetworkAddress client_address
IP-address of the client (so they can be banned).
Compose data into a growing std::string.
Parse data from a string / buffer.
bool ReadCharIf(char c)
Check whether the next 8-bit char matches 'c', and skip it.
void SkipCharIf(char c)
If the next data matches the 8-bit char 'c', then skip it.
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
void SkipUntilChar(char c, SeparatorUsage sep)
Skip data until the first occurrence of 8-bit char 'c'.
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
std::string_view Read(size_type len)
Read the next 'len' bytes, and advance reader.
static constexpr size_type npos
Special value for "end of data".
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
Definition network.cpp:781
void OnFailure() override
Callback for when the connection attempt failed.
Definition network.cpp:774
std::string connection_string
The address that this connecter is trying to connect to.
Definition network.cpp:765
TCPClientConnecter(std::string_view connection_string)
Create the connecter.
Definition network.cpp:772
static void CheckCallbacks()
Check whether we need to call the callback, i.e.
static std::shared_ptr< TCPConnecter > Create(Args &&... args)
Create the connecter, and initiate connecting by putting it in the collection of TCP connections to m...
Definition tcp.h:146
static void KillAll()
Kill all connection attempts.
TCPQueryConnecter(std::string_view connection_string)
Create the connecter.
Definition network.cpp:664
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
Definition network.cpp:677
std::string connection_string
The address that this connecter is trying to query.
Definition network.cpp:657
void OnFailure() override
Callback for when the connection attempt failed.
Definition network.cpp:666
TCPServerConnecter(std::string_view connection_string, uint16_t default_port)
Create a new connecter for the server.
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.
StrongType::Typedef< int32_t, DateTag< struct Economy >, StrongType::Compare, StrongType::Integer > Date
std::string_view GetCommandName(Commands cmd)
Get the name of the given command.
Definition command.cpp:125
Functions related to commands.
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, const CommandDataBuffer &cmd_data)
Prepare a DoCommand to be send over the network.
Commands
List of commands.
@ Pause
pause the game
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID GetFirstPlayableCompanyID()
Get the index of the first available company.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
static const uint16_t NETWORK_DEFAULT_PORT
The default port of the game server (TCP & UDP).
Definition config.h:23
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_DEFAULT
Default colour of the console.
void NetworkCoreShutdown()
Shuts down the network core (as that is needed for some platforms.
Definition core.cpp:42
bool NetworkCoreInitialize()
Initializes the network core (as that is needed for some platforms.
Definition core.cpp:22
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition core.h:26
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to errors.
@ 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
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
std::optional< FileHandle > FioFOpenFile(std::string_view filename, std::string_view mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition fileio.cpp:246
Functions for standard in/out file operations.
@ Save
Base directory for all savegames.
Definition fileio_type.h:90
PauseModes _pause_mode
The current pause mode.
Definition gfx.cpp:51
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
void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
Find the IPv4 broadcast addresses; IPv6 uses a completely different strategy for broadcasting.
Definition host.cpp:84
Resolving of hostnames/IPs.
void NetworkHTTPInitialize()
Initialize the HTTP socket handler.
void NetworkHTTPUninitialize()
Uninitialize the HTTP socket handler.
Types related to the landscape.
Miscellaneous command definitions.
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
NetworkAddress ParseConnectionString(std::string_view connection_string, uint16_t default_port)
Convert a string containing either "hostname" or "hostname:ip" to a NetworkAddress.
Definition network.cpp:566
void NetworkStartUp()
This tries to launch the network for a given OS.
Definition network.cpp:1323
bool _is_network_server
Does this client wants to be a network-server?
Definition network.cpp:71
void NetworkHandlePauseChange(PauseModes prev_mode, PauseMode changed_mode)
Handle the pause mode change so we send the right messages to the chat.
Definition network.cpp:363
static uint NetworkCountActiveClients()
Counts the number of active clients connected.
Definition network.cpp:430
StringList _network_host_list
The servers we know.
Definition network.cpp:76
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve a short translateable string of the error code.
Definition network.cpp:328
uint32_t _frame_counter_server
The frame_counter of the server, if in network-mode.
Definition network.cpp:78
static void CheckPauseOnJoin()
Check whether we should pause on join.
Definition network.cpp:472
NetworkAddressList _broadcast_list
List of broadcast addresses.
Definition network.cpp:82
void NetworkClientJoinGame()
Actually perform the joining to the server.
Definition network.cpp:842
static bool NetworkHasJoiningClient()
Checks whether there is a joining client.
Definition network.cpp:460
static auto FindKey(auto *authorized_keys, std::string_view authorized_key)
Simple helper to find the location of the given authorized key in the authorized keys.
Definition network.cpp:170
ClientID _redirect_console_to_client
If not invalid, redirect the console output to a client.
Definition network.cpp:73
static void CheckClientAndServerName()
Check whether the client and server name are set, for a dedicated server and if not set them to some ...
Definition network.cpp:902
uint8_t NetworkSpectatorCount()
Get the number of clients that are playing as a spectator.
Definition network.cpp:220
void NetworkOnGameStart()
Perform tasks when the server is started.
Definition network.cpp:979
uint32_t _frame_counter
The current frame.
Definition network.cpp:80
bool _network_available
is network mode available?
Definition network.cpp:69
bool NetworkServerStart()
Run everything related to the network when starting a server.
Definition network.cpp:923
uint8_t _network_reconnect
Reconnect timeout.
Definition network.cpp:74
bool _networking
are we in networking mode?
Definition network.cpp:67
static void NetworkInitialize(bool close_admins=true)
Initializes the network (cleans sockets and stuff).
Definition network.cpp:644
void NetworkQueryServer(std::string_view connection_string)
Query a server to fetch the game-info.
Definition network.cpp:689
static void InitializeNetworkPools(bool close_admins=true)
Resets the pools used for network clients, and the admin pool if needed.
Definition network.cpp:593
StringList _network_ban_list
The banned clients.
Definition network.cpp:77
static void NetworkSend()
This sends all buffered commands (if possible).
Definition network.cpp:1100
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:70
bool HasClients()
Return whether there is any client connected or trying to connect at all.
Definition network.cpp:99
static bool NetworkReceive()
Receives something from the network.
Definition network.cpp:1086
void NetworkGameLoop()
The main loop called from ttd.c.
Definition network.cpp:1132
void NetworkReboot()
The server is rebooting... The only difference with NetworkDisconnect, is the packets that is sent.
Definition network.cpp:1012
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:1035
bool _network_server
network-server is active
Definition network.cpp:68
std::string GenerateUid(std::string_view subject)
Generate an unique ID.
Definition misc.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
NetworkGame * NetworkAddServer(std::string_view connection_string, bool manually, bool never_expire)
Validates an address entered as a string and adds the server to the list.
Definition network.cpp:711
uint32_t _sync_frame
The frame to perform the sync check.
Definition network.cpp:87
void NetworkBackgroundLoop()
We have to do some (simple) background stuff that runs normally, even when we are not in multiplayer.
Definition network.cpp:1116
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:75
void ShowNetworkError(StringID error_string)
There was a non-recoverable error, drop back to the main menu with a nice error.
Definition network.cpp:316
std::string NormalizeConnectionString(std::string_view connection_string, uint16_t default_port)
Normalize a connection string.
Definition network.cpp:551
uint NetworkCalculateLag(const NetworkClientSocket *cs)
Calculate the frame-lag of a client.
Definition network.cpp:299
bool NetworkClientConnectGame(std::string_view connection_string, CompanyID default_company, const std::string &join_server_password)
Join a client to the server at with the given connection string.
Definition network.cpp:809
static void CheckMinActiveClients()
Check if the minimum number of active clients has been reached and pause or unpause the game as appro...
Definition network.cpp:446
void NetworkRebuildHostList()
Generates the list of manually added hosts from NetworkGame and dumps them into the array _network_ho...
Definition network.cpp:753
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:72
std::string_view ParseCompanyFromConnectionString(std::string_view connection_string, CompanyID *company_id)
Parse the company part ("#company" postfix) of a connecting string.
Definition network.cpp:487
static void CheckPauseHelper(bool pause, PauseMode pm)
Helper function for the pause checkers.
Definition network.cpp:418
bool _network_first_time
Whether we have finished joining or not.
Definition network.cpp:88
NetworkClientInfoPool _networkclientinfo_pool
Make sure both pools have the same size.
Definition network.cpp:64
void NetworkShutDown()
This shuts the network down.
Definition network.cpp:1341
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:91
static void NetworkInitGameInfo()
Initialise/fill the server's game info.
Definition network.cpp:856
static void NetworkInitServerClientInfo()
Initialise the server's client info.
Definition network.cpp:864
void GetBindAddresses(NetworkAddressList *addresses, uint16_t port)
Get the addresses to bind to.
Definition network.cpp:737
std::string_view ParseFullConnectionString(std::string_view connection_string, uint16_t &port, CompanyID *company_id)
Converts a string to ip/port/company Format: IP:port::company.
Definition network.cpp:531
void NetworkUpdateServerGameType()
The setting server_game_type was updated; possibly we need to take some action.
Definition network.cpp:1063
bool NetworkCanJoinCompany(CompanyID company_id)
Returns whether the given company can be joined by this client.
Definition network.cpp:143
void NetworkClose(bool close_admins)
Close current connections.
Definition network.cpp:604
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:79
bool NetworkValidateServerName(std::string &server_name)
Trim the given server name in place, i.e.
Definition network.cpp:887
Server part of the admin network protocol.
Base core network types and some helper functions to access them.
Pool< NetworkClientInfo, ClientPoolID, 8, PoolType::NetworkClient > NetworkClientInfoPool
Type for the pool with client information.
void NetworkAddChatMessage(TextColour colour, uint duration, const std::string &message)
Add a text message to the 'chat window' to be shown.
NetworkJoinInfo _network_join
Information about the game to join to.
bool NetworkValidateOurClientName()
Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
void NetworkClient_Connected()
Is called after a client is connected to the server.
Client part of the network protocol.
void NetworkFreeLocalCommandQueue()
Free the local command queues.
void NetworkExecuteLocalCommandQueue()
Execute all commands on the local command queue that ought to be executed this frame.
void NetworkDistributeCommands()
Distribute the commands of ourself and the clients.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
Part of the network protocol handling content distribution.
ClientNetworkCoordinatorSocketHandler _network_coordinator_client
The connection to the Game Coordinator.
Part of the network protocol handling Game Coordinator requests.
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci)
Perform all the server specific administration of a new company.
void NetworkServerUpdateGameInfo()
Update the server's NetworkServerGameInfo due to changes in settings.
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.
NetworkGame * NetworkGameListAddItem(std::string_view connection_string)
Add a new item to the linked gamelist.
std::vector< std::unique_ptr< NetworkGame > > _network_game_list
Game list of this client.
Handling of the list of games.
@ NGLS_OFFLINE
Server is offline (or cannot be queried).
NetworkJoinStatus _network_join_status
The status of joining.
void UpdateNetworkGameWindow()
Update the network new window because a new server is found on the network.
void ShowJoinStatusWindow()
Open the window showing the status of joining the server.
void ShowClientList()
Open the client list window.
GUIs related to networking.
@ Connecting
Opening the connection to the server.
class ServerNetworkGameSocketHandler NetworkClientSocket
Class for handling the server side of the game connection.
Query part of the network protocol.
void ChangeNetworkRestartTime(bool reset)
Reset the automatic network restart time interval.
void NetworkServer_Tick(bool send_frame)
This is called every tick if this is a _network_server.
Server part of the network protocol.
ServerNetworkGameSocketHandler NetworkClientSocket
Make the code look slightly nicer/simpler.
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.
@ 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.
@ ClientLeave
A client left the server.
@ CompanyNew
A client created an joined a new company.
@ CompanyJoin
A client joined an existing company.
@ GiveMoney
A company was given money.
@ Client
Send message/notice to only a certain client (Private).
ClientID
'Unique' identifier to be given to clients
@ CLIENT_ID_SERVER
Servers always have this ID.
@ Public
The game is publicly accessible.
@ Local
Do not communicate with the game coordinator.
@ InviteOnly
The game can be accessed if you know the invite code.
void NetworkUDPClose()
Close all UDP related stuff.
void NetworkUDPInitialize()
Initialize the whole UDP bit.
void NetworkUDPServerListen()
Start the listening of the UDP server component.
void NetworkBackgroundUDPLoop()
Receive the UDP packets.
Sending and receiving UDP messages.
void ClearGRFConfigList(GRFConfigList &config)
Clear a GRF Config list, freeing all nodes.
void StateGameLoop()
State controlling game loop.
Definition openttd.cpp:1208
PauseMode
Modes of pausing we've got.
Definition openttd.h:68
@ LinkGraph
A game paused due to the link graph schedule lagging.
Definition openttd.h:75
@ Error
A game paused because a (critical) error.
Definition openttd.h:72
@ GameScript
A game paused by a game script.
Definition openttd.h:74
@ ActiveClients
A game paused for 'min_active_clients'.
Definition openttd.h:73
@ Normal
A game normally paused.
Definition openttd.h:69
@ Join
A game paused for 'pause_on_join'.
Definition openttd.h:71
@ SM_JOIN_GAME
Join a network game.
Definition openttd.h:41
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
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.
@ NetworkClient
Network client pools.
Definition pool_type.hpp:18
@ NetworkAdmin
Network admin pool.
Definition pool_type.hpp:19
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.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
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 FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
bool StrEqualsIgnoreCase(std::string_view str1, std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
Definition string.cpp:325
void StrTrimInPlace(std::string &str)
Trim the spaces from given string in place, i.e.
Definition string.cpp:230
Compose strings from textual and binary data.
Parse strings.
static const char32_t CHAR_TD_LRM
The next character acts like a left-to-right character.
Definition string_type.h:35
static const char32_t CHAR_TD_RLM
The next character acts like a right-to-left character.
Definition string_type.h:36
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition strings.cpp:336
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
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_LTR
Text is written left-to-right by default.
Everything we need to know about a command to be able to execute it.
StringID err_msg
string ID of error message to use.
CommandDataBuffer data
command parameters.
CompanyID company
company that is executing the command
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.
StringID name_1
Name of the company if the user did not change it.
std::string name
Name of the company if the user changed it.
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
~NetworkClientInfo()
Basically a client is leaving us right now.
Definition network.cpp:107
bool CanJoinCompany(CompanyID company_id) const
Returns whether the given company can be joined by this client.
Definition network.cpp:132
CompanyID client_playas
As which company is this client playing (CompanyID).
ClientID client_id
Client identifier (same as ClientState->client_id).
NetworkClientInfo(ClientPoolID index, ClientID client_id=INVALID_CLIENT_ID)
Create a new client.
std::string client_name
Name of the client.
std::string public_key
The public key of the client.
Structure with information shown in the game list (GUI).
bool refreshing
Whether this server is being queried.
int version
Used to see which servers are no longer available on the Game Coordinator and can be removed.
NetworkGameInfo info
The game information of this server.
bool manually
True if the server was added manually.
NetworkGameStatus status
Stats of the server.
GRFConfigList grfconfig
List of NewGRF files used.
std::string server_name
Server name.
static void Clean(PoolTypes)
Clean all pools of given type.
Definition pool_func.cpp:30
static Pool::IterateWrapper< NetworkClientInfo > Iterate(size_t from=0)
static Company * GetIfValid(auto index)
The data required to format and validate a single parameter of a string.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Basic functions to receive and send UDP packets.
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:3322
Window functions not directly related to making/drawing windows.
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:45
@ WC_SEND_NETWORK_MSG
Chatbox; Window numbers:
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: