Changeset - r25824:08d7cb74dd5d
[Not reviewed]
master
0 5 0
Patric Stout - 3 years ago 2021-07-14 19:23:44
truebrain@openttd.org
Add: inform clients what game-script a server is running (#9441)

Co-authored-by: The Dude <thedude@novapolis.net>
5 files changed with 24 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/lang/english.txt
Show inline comments
 
@@ -2012,48 +2012,49 @@ STR_NETWORK_SERVER_LIST_GENERAL_ONLINE  
 
STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION                         :{BLACK}Clients
 
STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP                 :{BLACK}Clients online / clients max{}Companies online / companies max
 
STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT                          :{BLACK}{COMMA}x{COMMA}
 
STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION                        :{BLACK}Map size
 
STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP                :{BLACK}Map size of the game{}Click to sort by area
 
STR_NETWORK_SERVER_LIST_DATE_CAPTION                            :{BLACK}Date
 
STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP                    :{BLACK}Current date
 
STR_NETWORK_SERVER_LIST_YEARS_CAPTION                           :{BLACK}Years
 
STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP                   :{BLACK}Number of years{}the game is running
 
STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP                      :{BLACK}Language, server version, etc.
 

	
 
STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT                    :{BLACK}Click a game from the list to select it
 
STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER                      :{BLACK}The server you joined last time:
 
STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST                    :{BLACK}Click to select the server you played last time
 

	
 
STR_NETWORK_SERVER_LIST_GAME_INFO                               :{SILVER}GAME INFO
 
STR_NETWORK_SERVER_LIST_CLIENTS                                 :{SILVER}Clients: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA}
 
STR_NETWORK_SERVER_LIST_LANGUAGE                                :{SILVER}Language: {WHITE}{STRING}
 
STR_NETWORK_SERVER_LIST_LANDSCAPE                               :{SILVER}Landscape: {WHITE}{STRING}
 
STR_NETWORK_SERVER_LIST_MAP_SIZE                                :{SILVER}Map size: {WHITE}{COMMA}x{COMMA}
 
STR_NETWORK_SERVER_LIST_SERVER_VERSION                          :{SILVER}Server version: {WHITE}{RAW_STRING}
 
STR_NETWORK_SERVER_LIST_SERVER_ADDRESS                          :{SILVER}Server address: {WHITE}{RAW_STRING}
 
STR_NETWORK_SERVER_LIST_START_DATE                              :{SILVER}Start date: {WHITE}{DATE_SHORT}
 
STR_NETWORK_SERVER_LIST_CURRENT_DATE                            :{SILVER}Current date: {WHITE}{DATE_SHORT}
 
STR_NETWORK_SERVER_LIST_GAMESCRIPT                              :{SILVER}Game Script: {WHITE}{RAW_STRING} (v{NUM})
 
STR_NETWORK_SERVER_LIST_PASSWORD                                :{SILVER}Password protected!
 
STR_NETWORK_SERVER_LIST_SERVER_OFFLINE                          :{SILVER}SERVER OFFLINE
 
STR_NETWORK_SERVER_LIST_SERVER_FULL                             :{SILVER}SERVER FULL
 
STR_NETWORK_SERVER_LIST_VERSION_MISMATCH                        :{SILVER}VERSION MISMATCH
 
STR_NETWORK_SERVER_LIST_GRF_MISMATCH                            :{SILVER}NEWGRF MISMATCH
 

	
 
STR_NETWORK_SERVER_LIST_JOIN_GAME                               :{BLACK}Join game
 
STR_NETWORK_SERVER_LIST_REFRESH                                 :{BLACK}Refresh server
 
STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP                         :{BLACK}Refresh the server info
 

	
 
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET                  :{BLACK}Search internet
 
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP          :{BLACK}Search internet for public servers
 
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN                       :{BLACK}Search LAN
 
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP               :{BLACK}Search local area network for servers
 
STR_NETWORK_SERVER_LIST_ADD_SERVER                              :{BLACK}Add server
 
STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP                      :{BLACK}Adds a server to the list. This can either be a server address or an invite code
 
STR_NETWORK_SERVER_LIST_START_SERVER                            :{BLACK}Start server
 
STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP                    :{BLACK}Start your own server
 

	
 
STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE                    :{BLACK}Enter your name
 
STR_NETWORK_SERVER_LIST_ENTER_SERVER_ADDRESS                    :{BLACK}Enter server address or invite code
 

	
 
# Start new multiplayer server
 
STR_NETWORK_START_SERVER_CAPTION                                :{WHITE}Start new multiplayer game
src/network/core/config.h
Show inline comments
 
@@ -24,49 +24,49 @@ static const uint16 NETWORK_CONTENT_SERV
 
static const uint16 NETWORK_CONTENT_MIRROR_PORT     =   80;           ///< The default port of the content mirror (TCP)
 
static const uint16 NETWORK_DEFAULT_PORT            = 3979;           ///< The default port of the game server (TCP & UDP)
 
static const uint16 NETWORK_ADMIN_PORT              = 3977;           ///< The default port for admin network
 
static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT   = 3982;           ///< The default port debug-log is sent to (TCP)
 

	
 
static const uint16 UDP_MTU                         = 1460;           ///< Number of bytes we can pack in a single UDP packet
 
/*
 
 * Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future
 
 * to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8.
 
 *
 
 * Packets up to 32 KiB have the high bit not set:
 
 * 00000000 00000000 0bbbbbbb aaaaaaaa -> aaaaaaaa 0bbbbbbb
 
 * Send_uint16(GB(size, 0, 15)
 
 *
 
 * Packets up to 1 GiB, first uint16 has high bit set so it knows to read a
 
 * next uint16 for the remaining bits of the size.
 
 * 00dddddd cccccccc bbbbbbbb aaaaaaaa -> cccccccc 10dddddd aaaaaaaa bbbbbbbb
 
 * Send_uint16(GB(size, 16, 14) | 0b10 << 14)
 
 * Send_uint16(GB(size,  0, 16))
 
 */
 
static const uint16 TCP_MTU                         = 32767;          ///< Number of bytes we can pack in a single TCP packet
 
static const uint16 COMPAT_MTU                      = 1460;           ///< Number of bytes we can pack in a single packet for backward compatibility
 

	
 
static const byte NETWORK_GAME_ADMIN_VERSION        =    1;           ///< What version of the admin network do we use?
 
static const byte NETWORK_GAME_INFO_VERSION         =    4;           ///< What version of game-info do we use?
 
static const byte NETWORK_GAME_INFO_VERSION         =    5;           ///< What version of game-info do we use?
 
static const byte NETWORK_COMPANY_INFO_VERSION      =    6;           ///< What version of company info is this?
 
static const byte NETWORK_COORDINATOR_VERSION       =    2;           ///< What version of game-coordinator-protocol do we use?
 

	
 
static const uint NETWORK_NAME_LENGTH               =   80;           ///< The maximum length of the server name and map name, in bytes including '\0'
 
static const uint NETWORK_COMPANY_NAME_LENGTH       =  128;           ///< The maximum length of the company name, in bytes including '\0'
 
static const uint NETWORK_HOSTNAME_LENGTH           =   80;           ///< The maximum length of the host name, in bytes including '\0'
 
static const uint NETWORK_HOSTNAME_PORT_LENGTH      =   80 + 6;       ///< The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port number (with a max of 65536)
 
static const uint NETWORK_SERVER_ID_LENGTH          =   33;           ///< The maximum length of the network id of the servers, in bytes including '\0'
 
static const uint NETWORK_REVISION_LENGTH           =   33;           ///< The maximum length of the revision, in bytes including '\0'
 
static const uint NETWORK_PASSWORD_LENGTH           =   33;           ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
 
static const uint NETWORK_CLIENTS_LENGTH            =  200;           ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
 
static const uint NETWORK_CLIENT_NAME_LENGTH        =   25;           ///< The maximum length of a client's name, in bytes including '\0'
 
static const uint NETWORK_RCONCOMMAND_LENGTH        =  500;           ///< The maximum length of a rconsole command, in bytes including '\0'
 
static const uint NETWORK_GAMESCRIPT_JSON_LENGTH    = COMPAT_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than COMPAT_MTU including header (3 bytes)
 
static const uint NETWORK_CHAT_LENGTH               =  900;           ///< The maximum length of a chat message, in bytes including '\0'
 
static const uint NETWORK_CONTENT_FILENAME_LENGTH   =   48;           ///< The maximum length of a content's filename, in bytes including '\0'.
 
static const uint NETWORK_CONTENT_NAME_LENGTH       =   32;           ///< The maximum length of a content's name, in bytes including '\0'.
 
static const uint NETWORK_CONTENT_VERSION_LENGTH    =   16;           ///< The maximum length of a content's version, in bytes including '\0'.
 
static const uint NETWORK_CONTENT_URL_LENGTH        =   96;           ///< The maximum length of a content's url, in bytes including '\0'.
 
static const uint NETWORK_CONTENT_DESC_LENGTH       =  512;           ///< The maximum length of a content's description, in bytes including '\0'.
 
static const uint NETWORK_CONTENT_TAG_LENGTH        =   32;           ///< The maximum length of a content's tag, in bytes including '\0'.
 
static const uint NETWORK_ERROR_DETAIL_LENGTH       =  100;           ///< The maximum length of the error detail, in bytes including '\0'.
 
static const uint NETWORK_INVITE_CODE_LENGTH        =   64;           ///< The maximum length of the invite code, in bytes including '\0'.
 
static const uint NETWORK_INVITE_CODE_SECRET_LENGTH =   80;           ///< The maximum length of the invite code secret, in bytes including '\0'.
src/network/core/game_info.cpp
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * 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.
 
 * 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.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/**
 
 * @file game_info.cpp Functions to convert NetworkGameInfo to Packet and back.
 
 */
 

	
 
#include "../../stdafx.h"
 
#include "game_info.h"
 
#include "../../core/bitmath_func.hpp"
 
#include "../../company_base.h"
 
#include "../../date_func.h"
 
#include "../../debug.h"
 
#include "../../map_func.h"
 
#include "../../game/game.hpp"
 
#include "../../game/game_info.hpp"
 
#include "../../settings_type.h"
 
#include "../../string_func.h"
 
#include "../../rev.h"
 
#include "../network_func.h"
 
#include "../network.h"
 
#include "packet.h"
 

	
 
#include "../../safeguards.h"
 

	
 

	
 
/**
 
 * How many hex digits of the git hash to include in network revision string.
 
 * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix.
 
 */
 
static const uint GITHASH_SUFFIX_LEN = 12;
 

	
 
NetworkServerGameInfo _network_game_info; ///< Information about our game.
 

	
 
/**
 
 * Get the network version string used by this build.
 
 * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes including '\0' terminator.
 
 */
 
std::string_view GetNetworkRevisionString()
 
{
 
@@ -174,48 +176,53 @@ static void HandleIncomingNetworkGameInf
 
		config->name = f->name;
 
		config->info = f->info;
 
		config->url = f->url;
 
	}
 
	SetBit(config->flags, GCF_COPY);
 
}
 

	
 
/**
 
 * Serializes the NetworkGameInfo struct to the packet.
 
 * @param p    the packet to write the data to.
 
 * @param info the NetworkGameInfo struct to serialize from.
 
 */
 
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)
 
{
 
	p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in game_info.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 5 */
 
	GameInfo *game_info = Game::GetInfo();
 
	p->Send_uint32(game_info == nullptr ? -1 : (uint32)game_info->GetVersion());
 
	p->Send_string(game_info == nullptr ? "" : game_info->GetName());
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 4 */
 
	{
 
		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
 
		 * the GRFs that are needed, i.e. the ones that the server has
 
		 * selected in the NewGRF GUI and not the ones that are used due
 
		 * to the fact that they are in [newgrf-static] in openttd.cfg */
 
		const GRFConfig *c;
 
		uint count = 0;
 

	
 
		/* Count number of GRFs to send information about */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) count++;
 
		}
 
		p->Send_uint8 (count); // Send number of GRFs
 

	
 
		/* Send actual GRF Identifications */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident);
 
		}
 
	}
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 3 */
 
	p->Send_uint32(info->game_date);
 
	p->Send_uint32(info->start_date);
 
@@ -239,48 +246,54 @@ void SerializeNetworkGameInfo(Packet *p,
 
	p->Send_uint8 (info->landscape);
 
	p->Send_bool  (info->dedicated);
 
}
 

	
 
/**
 
 * Deserializes the NetworkGameInfo struct from the packet.
 
 * @param p    the packet to read the data from.
 
 * @param info the NetworkGameInfo to deserialize into.
 
 */
 
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
 
{
 
	static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
 

	
 
	byte game_info_version = p->Recv_uint8();
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in game_info.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	switch (game_info_version) {
 
		case 5: {
 
			info->gamescript_version = (int)p->Recv_uint32();
 
			info->gamescript_name = p->Recv_string(NETWORK_NAME_LENGTH);
 
			FALLTHROUGH;
 
		}
 

	
 
		case 4: {
 
			GRFConfig **dst = &info->grfconfig;
 
			uint i;
 
			uint num_grfs = p->Recv_uint8();
 

	
 
			/* Broken/bad data. It cannot have that many NewGRFs. */
 
			if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
 

	
 
			for (i = 0; i < num_grfs; i++) {
 
				GRFConfig *c = new GRFConfig();
 
				DeserializeGRFIdentifier(p, &c->ident);
 
				HandleIncomingNetworkGameInfoGRFConfig(c);
 

	
 
				/* Append GRFConfig to the list */
 
				*dst = c;
 
				dst = &c->next;
 
			}
 
			FALLTHROUGH;
 
		}
 

	
 
		case 3:
 
			info->game_date      = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			info->start_date     = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			FALLTHROUGH;
src/network/core/game_info.h
Show inline comments
 
@@ -55,48 +55,50 @@
 
 *                    (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland)
 
 *   1+       1       whether the server is dedicated (0 = no, 1 = yes)
 
 */
 

	
 
/**
 
 * The game information that is sent from the server to the client.
 
 */
 
struct NetworkServerGameInfo {
 
	GRFConfig *grfconfig;        ///< List of NewGRF files used
 
	Date start_date;             ///< When the game started
 
	Date game_date;              ///< Current date
 
	uint16 map_width;            ///< Map width
 
	uint16 map_height;           ///< Map height
 
	std::string server_name;     ///< Server name
 
	std::string server_revision; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
 
	bool dedicated;              ///< Is this a dedicated server?
 
	bool use_password;           ///< Is this server passworded?
 
	byte clients_on;             ///< Current count of clients on server
 
	byte clients_max;            ///< Max clients allowed on server
 
	byte companies_on;           ///< How many started companies do we have
 
	byte companies_max;          ///< Max companies allowed on server
 
	byte spectators_on;          ///< How many spectators do we have?
 
	byte spectators_max;         ///< Max spectators allowed on server
 
	byte landscape;              ///< The used landscape
 
	int gamescript_version;      ///< Version of the gamescript.
 
	std::string gamescript_name; ///< Name of the gamescript.
 
};
 

	
 
/**
 
 * The game information that is sent from the server to the clients
 
 * with extra information only required at the client side.
 
 */
 
struct NetworkGameInfo : NetworkServerGameInfo {
 
	bool version_compatible;                        ///< Can we connect to this server or not? (based on server_revision)
 
	bool compatible;                                ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
 
};
 

	
 
extern NetworkServerGameInfo _network_game_info;
 

	
 
std::string_view GetNetworkRevisionString();
 
bool IsNetworkCompatibleVersion(std::string_view other);
 
void CheckGameCompatibility(NetworkGameInfo &ngi);
 

	
 
void FillStaticNetworkServerGameInfo();
 
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo();
 

	
 
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
 
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);
 

	
 
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info);
src/network/network_gui.cpp
Show inline comments
 
@@ -654,48 +654,55 @@ public:
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParam(0, sel->info.map_width);
 
			SetDParam(1, sel->info.map_height);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); // map size
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParamStr(0, sel->info.server_revision);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParamStr(0, sel->connection_string);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParam(0, sel->info.start_date);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); // start date
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParam(0, sel->info.game_date);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			if (sel->info.gamescript_version != -1) {
 
				SetDParamStr(0, sel->info.gamescript_name);
 
				SetDParam(1, sel->info.gamescript_version);
 
				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_GAMESCRIPT); // gamescript name and version
 
				y += FONT_HEIGHT_NORMAL;
 
			}
 

	
 
			y += WD_PAR_VSEP_NORMAL;
 

	
 
			if (!sel->info.compatible) {
 
				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, sel->info.version_compatible ? STR_NETWORK_SERVER_LIST_GRF_MISMATCH : STR_NETWORK_SERVER_LIST_VERSION_MISMATCH, TC_FROMSTRING, SA_HOR_CENTER); // server mismatch
 
			} else if (sel->info.clients_on == sel->info.clients_max) {
 
				/* Show: server full, when clients_on == max_clients */
 
				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full
 
			} else if (sel->info.use_password) {
 
				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning
 
			}
 
		}
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_NG_CANCEL: // Cancel button
 
				CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
 
				break;
 

	
 
			case WID_NG_NAME:    // Sort by name
 
			case WID_NG_CLIENTS: // Sort by connected clients
 
			case WID_NG_MAPSIZE: // Sort by map size
 
			case WID_NG_DATE:    // Sort by date
0 comments (0 inline, 0 general)