OpenTTD Source 20260311-master-g511d3794ce
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
216uint8_t NetworkSpectatorCount()
217{
218 uint8_t count = 0;
219
221 if (ci->client_playas == COMPANY_SPECTATOR) count++;
222 }
223
224 /* Don't count a dedicated server as spectator */
225 if (_network_dedicated) count--;
226
227 return count;
228}
229
230
231/* This puts a text-message to the console, or in the future, the chat-box,
232 * (to keep it all a bit more general)
233 * If 'self_send' is true, this is the client who is sending the message */
234void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, std::string_view name, std::string_view str, StringParameter &&data)
235{
236 std::string message;
237 StringBuilder builder(message);
238
239 /* All of these strings start with "***". These characters are interpreted as both left-to-right and
240 * right-to-left characters depending on the context. As the next text might be an user's name, the
241 * user name's characters will influence the direction of the "***" instead of the language setting
242 * of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
243 builder.PutUtf8(_current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
244
245 switch (action) {
246 case NETWORK_ACTION_SERVER_MESSAGE:
247 /* Ignore invalid messages */
248 builder += GetString(STR_NETWORK_SERVER_MESSAGE, str);
249 colour = CC_DEFAULT;
250 break;
251 case NETWORK_ACTION_COMPANY_SPECTATOR:
252 colour = CC_DEFAULT;
253 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE, name);
254 break;
255 case NETWORK_ACTION_COMPANY_JOIN:
256 colour = CC_DEFAULT;
257 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN, name, str);
258 break;
259 case NETWORK_ACTION_COMPANY_NEW:
260 colour = CC_DEFAULT;
261 builder += GetString(STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW, name, std::move(data));
262 break;
263 case NETWORK_ACTION_JOIN:
264 /* Show the Client ID for the server but not for the client. */
265 builder += _network_server ?
266 GetString(STR_NETWORK_MESSAGE_CLIENT_JOINED_ID, name, std::move(data)) :
267 GetString(STR_NETWORK_MESSAGE_CLIENT_JOINED, name);
268 break;
269 case NETWORK_ACTION_LEAVE: builder += GetString(STR_NETWORK_MESSAGE_CLIENT_LEFT, name, std::move(data)); break;
270 case NETWORK_ACTION_NAME_CHANGE: builder += GetString(STR_NETWORK_MESSAGE_NAME_CHANGE, name, str); break;
271 case NETWORK_ACTION_GIVE_MONEY: builder += GetString(STR_NETWORK_MESSAGE_GIVE_MONEY, name, std::move(data), str); break;
272 case NETWORK_ACTION_KICKED: builder += GetString(STR_NETWORK_MESSAGE_KICKED, name, str); break;
273 case NETWORK_ACTION_CHAT_COMPANY: builder += GetString(self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, name, str); break;
274 case NETWORK_ACTION_CHAT_CLIENT: builder += GetString(self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, name, str); break;
275 case NETWORK_ACTION_EXTERNAL_CHAT: builder += GetString(STR_NETWORK_CHAT_EXTERNAL, std::move(data), name, str); break;
276 default: builder += GetString(STR_NETWORK_CHAT_ALL, name, str); break;
277 }
278
279 Debug(desync, 1, "msg: {:08x}; {:02x}; {}", TimerGameEconomy::date, TimerGameEconomy::date_fract, message);
280 IConsolePrint(colour, message);
281 NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
282}
283
284/* Calculate the frame-lag of a client */
285uint NetworkCalculateLag(const NetworkClientSocket *cs)
286{
287 int lag = cs->last_frame_server - cs->last_frame;
288 /* This client has missed their ACK packet after 1 DAY_TICKS..
289 * so we increase their lag for every frame that passes!
290 * The packet can be out by a max of _net_frame_freq */
291 if (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) {
292 lag += _frame_counter - (cs->last_frame_server + Ticks::DAY_TICKS + _settings_client.network.frame_freq);
293 }
294 return lag;
295}
296
297
298/* There was a non-recoverable error, drop back to the main menu with a nice
299 * error */
300void ShowNetworkError(StringID error_string)
301{
304}
305
313{
314 switch (err) {
315 default:
316 case NetworkErrorCode::General: return STR_NETWORK_ERROR_CLIENT_GENERAL;
317 case NetworkErrorCode::Desync: return STR_NETWORK_ERROR_CLIENT_DESYNC;
318 case NetworkErrorCode::SavegameFailed: return STR_NETWORK_ERROR_CLIENT_SAVEGAME;
319 case NetworkErrorCode::ConnectionLost: return STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST;
320 case NetworkErrorCode::IllegalPacket: return STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR;
321 case NetworkErrorCode::NewGRFMismatch: return STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH;
322 case NetworkErrorCode::NotAuthorized: return STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED;
323 case NetworkErrorCode::NotExpected: return STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED;
324 case NetworkErrorCode::WrongRevision: return STR_NETWORK_ERROR_CLIENT_WRONG_REVISION;
325 case NetworkErrorCode::NameInUse: return STR_NETWORK_ERROR_CLIENT_NAME_IN_USE;
326 case NetworkErrorCode::WrongPassword: return STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD;
327 case NetworkErrorCode::CompanyMismatch: return STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH;
328 case NetworkErrorCode::Kicked: return STR_NETWORK_ERROR_CLIENT_KICKED;
329 case NetworkErrorCode::Cheater: return STR_NETWORK_ERROR_CLIENT_CHEATER;
330 case NetworkErrorCode::ServerFull: return STR_NETWORK_ERROR_CLIENT_SERVER_FULL;
331 case NetworkErrorCode::TooManyCommands: return STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS;
332 case NetworkErrorCode::TimeoutPassword: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD;
333 case NetworkErrorCode::TimeoutComputer: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER;
334 case NetworkErrorCode::TimeoutMap: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP;
335 case NetworkErrorCode::TimeoutJoin: return STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN;
336 case NetworkErrorCode::InvalidClientName: return STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME;
337 case NetworkErrorCode::NotOnAllowList: return STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST;
338 case NetworkErrorCode::NoAuthenticationMethodAvailable: return STR_NETWORK_ERROR_CLIENT_NO_AUTHENTICATION_METHOD_AVAILABLE;
339 };
340}
341
347void NetworkHandlePauseChange(PauseModes prev_mode, PauseMode changed_mode)
348{
349 if (!_networking) return;
350
351 switch (changed_mode) {
353 case PauseMode::Join:
357 bool changed = _pause_mode.None() != prev_mode.None();
358 bool paused = _pause_mode.Any();
359 if (!paused && !changed) return;
360
361 std::string str;
362 if (!changed) {
363 std::array<StringParameter, 5> params{};
364 auto it = params.begin();
365 if (_pause_mode.Test(PauseMode::Normal)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL;
366 if (_pause_mode.Test(PauseMode::Join)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS;
367 if (_pause_mode.Test(PauseMode::GameScript)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT;
368 if (_pause_mode.Test(PauseMode::ActiveClients)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS;
369 if (_pause_mode.Test(PauseMode::LinkGraph)) *it++ = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH;
370 str = GetStringWithArgs(STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + std::distance(params.begin(), it) - 1, {params.begin(), it});
371 } else {
372 StringID reason;
373 switch (changed_mode) {
374 case PauseMode::Normal: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL; break;
375 case PauseMode::Join: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS; break;
376 case PauseMode::GameScript: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT; break;
377 case PauseMode::ActiveClients: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS; break;
378 case PauseMode::LinkGraph: reason = STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH; break;
379 default: NOT_REACHED();
380 }
381 str = GetString(paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED, reason);
382 }
383
384 NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, "", str);
385 break;
386 }
387
388 default:
389 return;
390 }
391}
392
393
402static void CheckPauseHelper(bool pause, PauseMode pm)
403{
404 if (pause == _pause_mode.Test(pm)) return;
405
406 Command<Commands::Pause>::Post(pm, pause);
407}
408
415{
416 uint count = 0;
417
418 for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
419 if (cs->status != NetworkClientSocket::STATUS_ACTIVE) continue;
420 if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue;
421 count++;
422 }
423
424 return count;
425}
426
431{
432 if (_pause_mode.Test(PauseMode::Error) ||
434 (_settings_client.network.min_active_clients == 0 && !_pause_mode.Test(PauseMode::ActiveClients))) {
435 return;
436 }
438}
439
445{
446 for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
447 if (cs->status >= NetworkClientSocket::STATUS_AUTHORIZED && cs->status < NetworkClientSocket::STATUS_ACTIVE) return true;
448 }
449
450 return false;
451}
452
456static void CheckPauseOnJoin()
457{
458 if (_pause_mode.Test(PauseMode::Error) ||
459 (!_settings_client.network.pause_on_join && !_pause_mode.Test(PauseMode::Join))) {
460 return;
461 }
463}
464
471std::string_view ParseCompanyFromConnectionString(std::string_view connection_string, CompanyID *company_id)
472{
473 std::string_view ip = connection_string;
474 if (company_id == nullptr) return ip;
475
476 size_t offset = ip.find_last_of('#');
477 if (offset != std::string::npos) {
478 std::string_view company_string = ip.substr(offset + 1);
479 ip = ip.substr(0, offset);
480
481 uint8_t company_value;
482 auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
483 if (err == std::errc()) {
484 if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
485 if (company_value > MAX_COMPANIES || company_value == 0) {
486 *company_id = COMPANY_SPECTATOR;
487 } else {
488 /* "#1" means the first company, which has index 0. */
489 *company_id = (CompanyID)(company_value - 1);
490 }
491 } else {
492 *company_id = (CompanyID)company_value;
493 }
494 }
495 }
496
497 return ip;
498}
499
515std::string_view ParseFullConnectionString(std::string_view connection_string, uint16_t &port, CompanyID *company_id)
516{
517 std::string_view ip = ParseCompanyFromConnectionString(connection_string, company_id);
518
519 size_t port_offset = ip.find_last_of(':');
520 size_t ipv6_close = ip.find_last_of(']');
521 if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) {
522 std::string_view port_string = ip.substr(port_offset + 1);
523 ip = ip.substr(0, port_offset);
524 std::from_chars(port_string.data(), port_string.data() + port_string.size(), port);
525 }
526 return ip;
527}
528
535std::string NormalizeConnectionString(std::string_view connection_string, uint16_t default_port)
536{
537 uint16_t port = default_port;
538 std::string_view ip = ParseFullConnectionString(connection_string, port);
539 return fmt::format("{}:{}", ip, port);
540}
541
550NetworkAddress ParseConnectionString(std::string_view connection_string, uint16_t default_port)
551{
552 uint16_t port = default_port;
553 std::string_view ip = ParseFullConnectionString(connection_string, port);
554 return NetworkAddress(ip, port);
555}
556
562/* static */ void ServerNetworkGameSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address)
563{
564 /* Register the login */
566
568 cs->client_address = address; // Save the IP of the client
569
571}
572
577static void InitializeNetworkPools(bool close_admins = true)
578{
579 PoolTypes to_clean{PoolType::NetworkClient};
580 if (close_admins) to_clean.Set(PoolType::NetworkAdmin);
581 PoolBase::Clean(to_clean);
582}
583
588void NetworkClose(bool close_admins)
589{
590 if (_network_server) {
591 if (close_admins) {
593 as->CloseConnection(true);
594 }
595 }
596
597 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
598 cs->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
599 }
602
603 _network_coordinator_client.CloseConnection();
604 } else {
605 if (MyClient::my_client != nullptr) {
608 }
609
610 _network_coordinator_client.CloseAllConnections();
611 }
613
615
616 _networking = false;
617 _network_server = false;
618
620
621 InitializeNetworkPools(close_admins);
622}
623
624/* Initializes the network (cleans sockets and stuff) */
625static void NetworkInitialize(bool close_admins = true)
626{
627 InitializeNetworkPools(close_admins);
628
629 _sync_frame = 0;
630 _network_first_time = true;
631
633}
634
636class TCPQueryConnecter : public TCPServerConnecter {
637private:
638 std::string connection_string;
639
640public:
641 TCPQueryConnecter(std::string_view connection_string) : TCPServerConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
642
643 void OnFailure() override
644 {
645 Debug(net, 9, "Query::OnFailure(): connection_string={}", this->connection_string);
646
647 NetworkGame *item = NetworkGameListAddItem(connection_string);
648 item->status = NGLS_OFFLINE;
649 item->refreshing = false;
650
652 }
653
654 void OnConnect(SOCKET s) override
655 {
656 Debug(net, 9, "Query::OnConnect(): connection_string={}", this->connection_string);
657
658 QueryNetworkGameSocketHandler::QueryServer(s, this->connection_string);
659 }
660};
661
666void NetworkQueryServer(std::string_view connection_string)
667{
668 if (!_network_available) return;
669
670 Debug(net, 9, "NetworkQueryServer(): connection_string={}", connection_string);
671
672 /* Mark the entry as refreshing, so the GUI can show the refresh is pending. */
673 NetworkGame *item = NetworkGameListAddItem(connection_string);
674 item->refreshing = true;
675
677}
678
688NetworkGame *NetworkAddServer(std::string_view connection_string, bool manually, bool never_expire)
689{
690 if (connection_string.empty()) return nullptr;
691
692 /* Ensure the item already exists in the list */
693 NetworkGame *item = NetworkGameListAddItem(connection_string);
694 if (item->info.server_name.empty()) {
696 item->info.server_name = connection_string;
697
699
700 NetworkQueryServer(connection_string);
701 }
702
703 if (manually) item->manually = true;
704 if (never_expire) item->version = INT32_MAX;
705
706 return item;
707}
708
714void GetBindAddresses(NetworkAddressList *addresses, uint16_t port)
715{
716 for (const auto &iter : _network_bind_list) {
717 addresses->emplace_back(iter, port);
718 }
719
720 /* No address, so bind to everything. */
721 if (addresses->empty()) {
722 addresses->emplace_back("", port);
723 }
724}
725
731{
732 _network_host_list.clear();
733
734 for (const auto &item : _network_game_list) {
735 if (item->manually) _network_host_list.emplace_back(item->connection_string);
736 }
737}
738
740class TCPClientConnecter : public TCPServerConnecter {
741private:
742 std::string connection_string;
743
744public:
745 TCPClientConnecter(std::string_view connection_string) : TCPServerConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
746
747 void OnFailure() override
748 {
749 Debug(net, 9, "Client::OnFailure(): connection_string={}", this->connection_string);
750
751 ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION);
752 }
753
754 void OnConnect(SOCKET s) override
755 {
756 Debug(net, 9, "Client::OnConnect(): connection_string={}", this->connection_string);
757
758 _networking = true;
760 new ClientNetworkGameSocketHandler(s, this->connection_string);
761 IConsoleCmdExec("exec scripts/on_client.scr 0");
763 }
764};
765
782bool NetworkClientConnectGame(std::string_view connection_string, CompanyID default_company, const std::string &join_server_password)
783{
784 Debug(net, 9, "NetworkClientConnectGame(): connection_string={}", connection_string);
785
786 CompanyID join_as = default_company;
787 std::string resolved_connection_string = ServerAddress::Parse(connection_string, NETWORK_DEFAULT_PORT, &join_as).connection_string;
788
789 if (!_network_available) return false;
790 if (!NetworkValidateOurClientName()) return false;
791
792 _network_join.connection_string = std::move(resolved_connection_string);
793 _network_join.company = join_as;
794 _network_join.server_password = join_server_password;
795
796 if (_game_mode == GM_MENU) {
797 /* From the menu we can immediately continue with the actual join. */
799 } else {
800 /* When already playing a game, first go back to the main menu. This
801 * disconnects the user from the current game, meaning we can safely
802 * load in the new. After all, there is little point in continuing to
803 * play on a server if we are connecting to another one.
804 */
806 }
807 return true;
808}
809
816{
818 NetworkInitialize();
819
820 _settings_client.network.last_joined = _network_join.connection_string;
821 Debug(net, 9, "status = Connecting");
823 ShowJoinStatusWindow();
824
826}
827
828static void NetworkInitGameInfo()
829{
831 /* The server is a client too */
832 _network_game_info.clients_on = _network_dedicated ? 0 : 1;
833
834 /* There should be always space for the server. */
838
839 ci->client_name = _settings_client.network.client_name;
840
842 ci->public_key = _settings_client.network.client_public_key;
843}
844
855bool NetworkValidateServerName(std::string &server_name)
856{
857 StrTrimInPlace(server_name);
858 if (!server_name.empty()) return true;
859
860 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_BAD_SERVER_NAME), {}, WL_ERROR);
861 return false;
862}
863
871{
872 static const std::string fallback_client_name = "Unnamed Client";
873 StrTrimInPlace(_settings_client.network.client_name);
874 if (_settings_client.network.client_name.empty() || _settings_client.network.client_name == fallback_client_name) {
875 Debug(net, 1, "No \"client_name\" has been set, using \"{}\" instead. Please set this now using the \"name <new name>\" command", fallback_client_name);
876 _settings_client.network.client_name = fallback_client_name;
877 }
878
879 static const std::string fallback_server_name = "Unnamed Server";
880 StrTrimInPlace(_settings_client.network.server_name);
881 if (_settings_client.network.server_name.empty() || _settings_client.network.server_name == fallback_server_name) {
882 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);
883 _settings_client.network.server_name = fallback_server_name;
884 }
885}
886
887bool NetworkServerStart()
888{
889 if (!_network_available) return false;
890
891 /* Call the pre-scripts */
892 IConsoleCmdExec("exec scripts/pre_server.scr 0");
893 if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
894
895 /* Check for the client and server names to be set, but only after the scripts had a chance to set them.*/
897
898 NetworkDisconnect(false);
899 NetworkInitialize(false);
901 Debug(net, 5, "Starting listeners for clients");
902 if (!ServerNetworkGameSocketHandler::Listen(_settings_client.network.server_port)) return false;
903
904 /* Only listen for admins when the authentication is configured. */
905 if (_settings_client.network.AdminAuthenticationConfigured()) {
906 Debug(net, 5, "Starting listeners for admins");
907 if (!ServerNetworkAdminSocketHandler::Listen(_settings_client.network.server_admin_port)) return false;
908 }
909
910 /* Try to start UDP-server */
911 Debug(net, 5, "Starting listeners for incoming server queries");
913
914 _network_server = true;
915 _networking = true;
916 _frame_counter = 0;
921
923
924 NetworkInitGameInfo();
925
926 if (_settings_client.network.server_game_type != ServerGameType::Local) {
928 }
929
930 /* execute server initialization script */
931 IConsoleCmdExec("exec scripts/on_server.scr 0");
932 /* if the server is dedicated ... add some other script */
933 if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
934
935 return true;
936}
937
943{
944 if (!_network_server) return;
945
946 /* Update the static game info to set the values from the new game. */
948
950
951 if (!_network_dedicated) {
954 if (c != nullptr && ci != nullptr) {
955 ci->client_playas = c->index;
956
957 /*
958 * If the company has not been named yet, the company was just started.
959 * Otherwise it would have gotten a name already, so announce it as a new company.
960 */
961 if (c->name_1 == STR_SV_UNNAMED && c->name.empty()) NetworkServerNewCompany(c, ci);
962 }
963
964 ShowClientList();
965 } else {
966 /* welcome possibly still connected admins - this can only happen on a dedicated server. */
968 }
969}
970
976{
977 if (_network_server) {
978 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
979 cs->SendNewGame();
980 cs->SendPackets();
981 }
982
984 as->SendNewGame();
985 as->SendPackets();
986 }
987 }
988
989 /* For non-dedicated servers we have to kick the admins as we are not
990 * certain that we will end up in a new network game. */
992}
993
998void NetworkDisconnect(bool close_admins)
999{
1000 if (_network_server) {
1001 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1002 cs->SendShutdown();
1003 cs->SendPackets();
1004 }
1005
1006 if (close_admins) {
1008 as->SendShutdown();
1009 as->SendPackets();
1010 }
1011 }
1012 }
1013
1015
1016 NetworkClose(close_admins);
1017
1018 /* Reinitialize the UDP stack, i.e. close all existing connections. */
1020}
1021
1027{
1028 if (!_networking) return;
1029
1030 switch (_settings_client.network.server_game_type) {
1032 _network_coordinator_client.CloseConnection();
1033 break;
1034
1037 _network_coordinator_client.Register();
1038 break;
1039
1040 default:
1041 NOT_REACHED();
1042 }
1043}
1044
1049static bool NetworkReceive()
1050{
1051 bool result;
1052 if (_network_server) {
1055 } else {
1057 }
1059 return result;
1060}
1061
1073
1090
1096{
1097 if (!_networking) return;
1098
1099 if (!NetworkReceive()) return;
1100
1101 if (_network_server) {
1102 /* Log the sync state to check for in-syncedness of replays. */
1104 /* We don't want to log multiple times if paused. */
1105 static TimerGameEconomy::Date last_log;
1106 if (last_log != TimerGameEconomy::date) {
1107 Debug(desync, 1, "sync: {:08x}; {:02x}; {:08x}; {:08x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _random.state[0], _random.state[1]);
1108 last_log = TimerGameEconomy::date;
1109 }
1110 }
1111
1112#ifdef DEBUG_DUMP_COMMANDS
1113 /* Loading of the debug commands from -ddesync>=1 */
1114 static auto f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
1115 static TimerGameEconomy::Date next_date(0);
1116 static uint32_t next_date_fract;
1117 static CommandPacket *cp = nullptr;
1118 static bool check_sync_state = false;
1119 static uint32_t sync_state[2];
1120 if (!f.has_value() && next_date == 0) {
1121 Debug(desync, 0, "Cannot open commands.log");
1122 next_date = TimerGameEconomy::Date(1);
1123 }
1124
1125 while (f.has_value() && !feof(*f)) {
1126 if (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract == next_date_fract) {
1127 if (cp != nullptr) {
1128 NetworkSendCommand(cp->cmd, cp->err_msg, nullptr, cp->company, cp->data);
1129 Debug(desync, 0, "Injecting: {:08x}; {:02x}; {:02x}; {:08x}; {} ({})", TimerGameEconomy::date, TimerGameEconomy::date_fract, _current_company.base(), cp->cmd, FormatArrayAsHex(cp->data), GetCommandName(cp->cmd));
1130 delete cp;
1131 cp = nullptr;
1132 }
1133 if (check_sync_state) {
1134 if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
1135 Debug(desync, 0, "Sync check: {:08x}; {:02x}; match", TimerGameEconomy::date, TimerGameEconomy::date_fract);
1136 } else {
1137 Debug(desync, 0, "Sync check: {:08x}; {:02x}; mismatch expected {{{:08x}, {:08x}}}, got {{{:08x}, {:08x}}}",
1138 TimerGameEconomy::date, TimerGameEconomy::date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
1139 NOT_REACHED();
1140 }
1141 check_sync_state = false;
1142 }
1143 }
1144
1145 /* Skip all entries in the command-log till we caught up with the current game again. */
1146 if (TimerGameEconomy::date > next_date || (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract > next_date_fract)) {
1147 Debug(desync, 0, "Skipping to next command at {:08x}:{:02x}", next_date, next_date_fract);
1148 if (cp != nullptr) {
1149 delete cp;
1150 cp = nullptr;
1151 }
1152 check_sync_state = false;
1153 }
1154
1155 if (cp != nullptr || check_sync_state) break;
1156
1157 char buff[4096];
1158 if (fgets(buff, lengthof(buff), *f) == nullptr) break;
1159
1160 StringConsumer consumer{std::string_view{buff}};
1161 /* Ignore the "[date time] " part of the message */
1162 if (consumer.ReadCharIf('[')) {
1164 consumer.SkipCharIf(' ');
1165 }
1166
1167 if (consumer.ReadIf("cmd: ")
1168#ifdef DEBUG_FAILED_DUMP_COMMANDS
1169 || consumer.ReadIf("cmdf: ")
1170#endif
1171 ) {
1172 cp = new CommandPacket();
1173 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1174 bool valid = consumer.ReadIf("; ");
1175 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1176 valid &= consumer.ReadIf("; ");
1177 cp->company = static_cast<CompanyID>(consumer.ReadIntegerBase<uint16_t>(16));
1178 valid &= consumer.ReadIf("; ");
1179 cp->cmd = static_cast<Commands>(consumer.ReadIntegerBase<uint32_t>(16));
1180 valid &= consumer.ReadIf("; ");
1181 cp->err_msg = consumer.ReadIntegerBase<uint32_t>(16);
1182 valid &= consumer.ReadIf("; ");
1183 auto args = consumer.ReadUntilChar(' ', StringConsumer::SKIP_ONE_SEPARATOR);
1184 assert(valid);
1185
1186 /* Parse command data. */
1187 cp->data.clear();
1188 for (size_t i = 0; i + 1 < args.size(); i += 2) {
1189 uint8_t e = 0;
1190 std::from_chars(args.data() + i, args.data() + i + 2, e, 16);
1191 cp->data.push_back(e);
1192 }
1193 } else if (consumer.ReadIf("join: ")) {
1194 /* Manually insert a pause when joining; this way the client can join at the exact right time. */
1195 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1196 bool valid = consumer.ReadIf("; ");
1197 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1198 assert(valid);
1199 Debug(desync, 0, "Injecting pause for join at {:08x}:{:02x}; please join when paused", next_date, next_date_fract);
1200 cp = new CommandPacket();
1202 cp->cmd = Commands::Pause;
1203 cp->data = EndianBufferWriter<>::FromValue(CommandTraits<Commands::Pause>::Args{ PauseMode::Normal, true });
1204 _ddc_fastforward = false;
1205 } else if (consumer.ReadIf("sync: ")) {
1206 next_date = TimerGameEconomy::Date(consumer.ReadIntegerBase<uint32_t>(16));
1207 bool valid = consumer.ReadIf("; ");
1208 next_date_fract = consumer.ReadIntegerBase<uint32_t>(16);
1209 valid &= consumer.ReadIf("; ");
1210 sync_state[0] = consumer.ReadIntegerBase<uint32_t>(16);
1211 valid &= consumer.ReadIf("; ");
1212 sync_state[1] = consumer.ReadIntegerBase<uint32_t>(16);
1213 assert(valid);
1214 check_sync_state = true;
1215 } else if (consumer.ReadIf("msg: ") || consumer.ReadIf("client: ") ||
1216 consumer.ReadIf("load: ") || consumer.ReadIf("save: ") ||
1217 consumer.ReadIf("warning: ")) {
1218 /* A message that is not very important to the log playback, but part of the log. */
1219#ifndef DEBUG_FAILED_DUMP_COMMANDS
1220 } else if (consumer.ReadIf("cmdf: ")) {
1221 Debug(desync, 0, "Skipping replay of failed command: {}", consumer.Read(StringConsumer::npos));
1222#endif
1223 } else {
1224 /* Can't parse a line; what's wrong here? */
1225 Debug(desync, 0, "Trying to parse: {}", consumer.Read(StringConsumer::npos));
1226 NOT_REACHED();
1227 }
1228 }
1229 if (f.has_value() && feof(*f)) {
1230 Debug(desync, 0, "End of commands.log");
1231 f.reset();
1232 }
1233#endif /* DEBUG_DUMP_COMMANDS */
1235 /* Only check for active clients just before we're going to send out
1236 * the commands so we don't send multiple pause/unpause commands when
1237 * the frame_freq is more than 1 tick. Same with distributing commands. */
1241 }
1242
1243 bool send_frame = false;
1244
1245 /* We first increase the _frame_counter */
1247 /* Update max-frame-counter */
1249 _frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
1250 send_frame = true;
1251 }
1252
1254
1255 /* Then we make the frame */
1256 StateGameLoop();
1257
1258 _sync_seed_1 = _random.state[0];
1259#ifdef NETWORK_SEND_DOUBLE_SEED
1260 _sync_seed_2 = _random.state[1];
1261#endif
1262
1263 NetworkServer_Tick(send_frame);
1264 } else {
1265 /* Client */
1266
1267 /* Make sure we are at the frame were the server is (quick-frames) */
1269 /* Run a number of frames; when things go bad, get out. */
1272 }
1273 } else {
1274 /* Else, keep on going till _frame_counter_max */
1276 /* Run one frame; if things went bad, get out. */
1278 }
1279 }
1280 }
1281
1282 NetworkSend();
1283}
1284
1287{
1288 Debug(net, 3, "Starting network");
1289
1290 /* Network is available */
1292 _network_dedicated = false;
1293
1294 _network_game_info = {};
1295
1296 NetworkInitialize();
1298 Debug(net, 3, "Network online, multiplayer available");
1301}
1302
1305{
1309
1310 Debug(net, 3, "Shutting down network");
1311
1312 _network_available = false;
1313
1315}
1316
1317#ifdef __EMSCRIPTEN__
1318extern "C" {
1319
1320void CDECL em_openttd_add_server(const char *connection_string)
1321{
1322 NetworkAddServer(connection_string, false, true);
1323}
1324
1325}
1326#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.
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:525
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:562
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:754
void OnFailure() override
Callback for when the connection attempt failed.
Definition network.cpp:747
std::string connection_string
Current address we are connecting to (before resolving).
Definition tcp.h:100
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.
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
Definition network.cpp:654
void OnFailure() override
Callback for when the connection attempt failed.
Definition network.cpp:643
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.
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:244
Functions for standard in/out file operations.
@ SAVE_DIR
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:550
void NetworkStartUp()
This tries to launch the network for a given OS.
Definition network.cpp:1286
bool _is_network_server
Does this client wants to be a network-server?
Definition network.cpp:71
NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo")
Make sure both pools have the same size.
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:347
static uint NetworkCountActiveClients()
Counts the number of active clients connected.
Definition network.cpp:414
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:312
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:456
NetworkAddressList _broadcast_list
List of broadcast addresses.
Definition network.cpp:82
void NetworkClientJoinGame()
Actually perform the joining to the server.
Definition network.cpp:815
static bool NetworkHasJoiningClient()
Checks whether there is a joining client.
Definition network.cpp:444
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:870
void NetworkOnGameStart()
Perform tasks when the server is started.
Definition network.cpp:942
uint32_t _frame_counter
The current frame.
Definition network.cpp:80
bool _network_available
is network mode available?
Definition network.cpp:69
uint8_t _network_reconnect
Reconnect timeout.
Definition network.cpp:74
bool _networking
are we in networking mode?
Definition network.cpp:67
void NetworkQueryServer(std::string_view connection_string)
Query a server to fetch the game-info.
Definition network.cpp:666
static void InitializeNetworkPools(bool close_admins=true)
Resets the pools used for network clients, and the admin pool if needed.
Definition network.cpp:577
StringList _network_ban_list
The banned clients.
Definition network.cpp:77
static void NetworkSend()
This sends all buffered commands (if possible).
Definition network.cpp:1063
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:1049
void NetworkGameLoop()
The main loop called from ttd.c.
Definition network.cpp:1095
void NetworkReboot()
The server is rebooting... The only difference with NetworkDisconnect, is the packets that is sent.
Definition network.cpp:975
void NetworkDisconnect(bool close_admins)
We want to disconnect from the host/clients.
Definition network.cpp:998
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
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:688
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:1079
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:75
std::string NormalizeConnectionString(std::string_view connection_string, uint16_t default_port)
Normalize a connection string.
Definition network.cpp:535
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:782
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:430
void NetworkRebuildHostList()
Generates the list of manually added hosts from NetworkGame and dumps them into the array _network_ho...
Definition network.cpp:730
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:471
static void CheckPauseHelper(bool pause, PauseMode pm)
Helper function for the pause checkers.
Definition network.cpp:402
bool _network_first_time
Whether we have finished joining or not.
Definition network.cpp:88
void NetworkShutDown()
This shuts the network down.
Definition network.cpp:1304
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:91
void GetBindAddresses(NetworkAddressList *addresses, uint16_t port)
Get the addresses to bind to.
Definition network.cpp:714
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:515
void NetworkUpdateServerGameType()
The setting server_game_type was updated; possibly we need to take some action.
Definition network.cpp:1026
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:588
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:855
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.
GUIs related to networking.
@ Connecting
Opening the connection to the server.
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.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private).
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.
@ 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:3321
Window functions not directly related to making/drawing windows.
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition window_type.h:44
@ WC_SEND_NETWORK_MSG
Chatbox; Window numbers:
@ WC_CLIENT_LIST
Client list; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: