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
 
@@ -1988,96 +1988,97 @@ STR_FACE_LIPS_MOUSTACHE_TOOLTIP         
 
STR_FACE_CHIN                                                   :Chin:
 
STR_FACE_CHIN_TOOLTIP                                           :{BLACK}Change chin
 
STR_FACE_JACKET                                                 :Jacket:
 
STR_FACE_JACKET_TOOLTIP                                         :{BLACK}Change jacket
 
STR_FACE_COLLAR                                                 :Collar:
 
STR_FACE_COLLAR_TOOLTIP                                         :{BLACK}Change collar
 
STR_FACE_TIE                                                    :Tie:
 
STR_FACE_EARRING                                                :Earring:
 
STR_FACE_TIE_EARRING_TOOLTIP                                    :{BLACK}Change tie or earring
 

	
 
############ Next lines match ServerGameType
 
STR_NETWORK_SERVER_VISIBILITY_LOCAL                             :Local
 
STR_NETWORK_SERVER_VISIBILITY_PUBLIC                            :Public
 
STR_NETWORK_SERVER_VISIBILITY_INVITE_ONLY                       :Invite only
 
############ End of leave-in-this-order
 

	
 
# Network server list
 
STR_NETWORK_SERVER_LIST_CAPTION                                 :{WHITE}Multiplayer
 
STR_NETWORK_SERVER_LIST_PLAYER_NAME                             :{BLACK}Player name:
 
STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP                      :{BLACK}This is the name other players will identify you by
 

	
 
STR_NETWORK_SERVER_LIST_GAME_NAME                               :{BLACK}Name
 
STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP                       :{BLACK}Name of the game
 
STR_NETWORK_SERVER_LIST_GENERAL_ONLINE                          :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA}
 
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
 

	
 
STR_NETWORK_START_SERVER_NEW_GAME_NAME                          :{BLACK}Game name:
 
STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP                  :{BLACK}The game name will be displayed to other players in the multiplayer game selection menu
 
STR_NETWORK_START_SERVER_SET_PASSWORD                           :{BLACK}Set password
 
STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP                       :{BLACK}Protect your game with a password if you don't want it to be publicly accessible
 

	
 
STR_NETWORK_START_SERVER_VISIBILITY_LABEL                       :{BLACK}Visibility
 
STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP                     :{BLACK}Whether other people can see your server in the public listing
 
STR_NETWORK_START_SERVER_CLIENTS_SELECT                         :{BLACK}{NUM} client{P "" s}
 
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS                      :{BLACK}Maximum number of clients:
 
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP              :{BLACK}Choose the maximum number of clients. Not all slots need to be filled
 
STR_NETWORK_START_SERVER_COMPANIES_SELECT                       :{BLACK}{NUM} compan{P y ies}
 
STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES                    :{BLACK}Maximum number of companies:
 
STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP            :{BLACK}Limit the server to a certain amount of companies
 
STR_NETWORK_START_SERVER_SPECTATORS_SELECT                      :{BLACK}{NUM} spectator{P "" s}
 
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS                   :{BLACK}Maximum number of spectators:
 
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP           :{BLACK}Limit the server to a certain amount of spectators
 
STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN                        :{BLACK}Language spoken:
 
STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP                       :{BLACK}Other players will know which language is spoken on the server
 

	
 
STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE                 :{BLACK}Enter a name for the network game
 

	
 
# Network game lobby
 
STR_NETWORK_GAME_LOBBY_CAPTION                                  :{WHITE}Multiplayer game lobby
src/network/core/config.h
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 config.h Configuration options of the network stuff. It is used even when compiling without network support.
 
 */
 

	
 
#ifndef NETWORK_CORE_CONFIG_H
 
#define NETWORK_CORE_CONFIG_H
 

	
 
const char *NetworkCoordinatorConnectionString();
 
const char *NetworkContentServerConnectionString();
 
const char *NetworkContentMirrorConnectionString();
 

	
 
/** URL of the HTTP mirror system */
 
static const char * const NETWORK_CONTENT_MIRROR_URL            = "/bananas";
 

	
 
static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976;           ///< The default port of the Game Coordinator server (TCP)
 
static const uint16 NETWORK_CONTENT_SERVER_PORT     = 3978;           ///< The default port of the content server (TCP)
 
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'.
 
static const uint NETWORK_TOKEN_LENGTH              =   64;           ///< The maximum length of a token, in bytes including '\0'.
 

	
 
static const uint NETWORK_GRF_NAME_LENGTH           =   80;           ///< Maximum length of the name of a GRF
 

	
 
/**
 
 * Maximum number of GRFs that can be sent.
 
 *
 
 * This limit exists to avoid that the SERVER_INFO packet exceeding the
 
 * maximum MTU. At the time of writing this limit is 32767 (TCP_MTU).
 
 *
 
 * In the SERVER_INFO packet is the NetworkGameInfo struct, which is
 
 * 142 bytes + 100 per NewGRF (under the assumption strings are used to
 
 * their max). This brings us to roughly 326 possible NewGRFs. Round it
 
 * down so people don't freak out because they see a weird value, and you
 
 * get the limit: 255.
 
 *
 
 * PS: in case you ever want to raise this number, please be mindful that
 
 * "amount of NewGRFs" in NetworkGameInfo is currently an uint8.
 
 */
 
static const uint NETWORK_MAX_GRF_COUNT             =   255;
 

	
 
/**
 
 * The number of landscapes in OpenTTD.
 
 * This number must be equal to NUM_LANDSCAPE, but as this number is used
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()
 
{
 
	static std::string network_revision;
 

	
 
	if (network_revision.empty()) {
 
		network_revision = _openttd_revision;
 
		if (_openttd_revision_tagged) {
 
			/* Tagged; do not mangle further, though ensure it's not too long. */
 
			if (network_revision.size() >= NETWORK_REVISION_LENGTH) network_revision.resize(NETWORK_REVISION_LENGTH - 1);
 
		} else {
 
			/* Not tagged; add the githash suffix while ensuring the string does not become too long. */
 
			assert(_openttd_revision_modified < 3);
 
			std::string githash_suffix = fmt::format("-{}{}", "gum"[_openttd_revision_modified], _openttd_revision_hash);
 
			if (githash_suffix.size() > GITHASH_SUFFIX_LEN) githash_suffix.resize(GITHASH_SUFFIX_LEN);
 

	
 
			/* Where did the hash start in the original string? Overwrite from that position, unless that would create a too long string. */
 
			size_t hash_end = network_revision.find_last_of('-');
 
			if (hash_end == std::string::npos) hash_end = network_revision.size();
 
			if (hash_end + githash_suffix.size() >= NETWORK_REVISION_LENGTH) hash_end = NETWORK_REVISION_LENGTH - githash_suffix.size() - 1;
 

	
 
			/* Replace the git hash in revision string. */
 
			network_revision.replace(hash_end, std::string::npos, githash_suffix);
 
		}
 
		assert(network_revision.size() < NETWORK_REVISION_LENGTH); // size does not include terminator, constant does, hence strictly less than
 
		Debug(net, 3, "Network revision name: {}", network_revision);
 
	}
 
@@ -150,161 +152,172 @@ const NetworkServerGameInfo *GetCurrentN
 
	_network_game_info.spectators_on = NetworkSpectatorCount();
 
	_network_game_info.game_date     = _date;
 
	return &_network_game_info;
 
}
 

	
 
/**
 
 * Function that is called for every GRFConfig that is read when receiving
 
 * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This
 
 * function must set all appropriate fields. This GRF is later appended to
 
 * the grfconfig list of the NetworkGameInfo.
 
 * @param config the GRF to handle.
 
 */
 
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
 
{
 
	/* Find the matching GRF file */
 
	const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
 
	if (f == nullptr) {
 
		/* Don't know the GRF, so mark game incompatible and the (possibly)
 
		 * already resolved name for this GRF (another server has sent the
 
		 * name of the GRF already */
 
		config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true);
 
		config->status = GCS_NOT_FOUND;
 
	} else {
 
		config->filename = f->filename;
 
		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);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 2 */
 
	p->Send_uint8 (info->companies_max);
 
	p->Send_uint8 (info->companies_on);
 
	p->Send_uint8 (info->spectators_max);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 1 */
 
	p->Send_string(info->server_name);
 
	p->Send_string(info->server_revision);
 
	p->Send_uint8 (0); // Used to be server-lang.
 
	p->Send_bool  (info->use_password);
 
	p->Send_uint8 (info->clients_max);
 
	p->Send_uint8 (info->clients_on);
 
	p->Send_uint8 (info->spectators_on);
 
	p->Send_string(""); // Used to be map-name.
 
	p->Send_uint16(info->map_width);
 
	p->Send_uint16(info->map_height);
 
	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;
 

	
 
		case 2:
 
			info->companies_max  = p->Recv_uint8 ();
 
			info->companies_on   = p->Recv_uint8 ();
 
			info->spectators_max = p->Recv_uint8 ();
 
			FALLTHROUGH;
 

	
 
		case 1:
 
			info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
 
			info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
 
			p->Recv_uint8 (); // Used to contain server-lang.
 
			info->use_password   = p->Recv_bool  ();
 
			info->clients_max    = p->Recv_uint8 ();
 
			info->clients_on     = p->Recv_uint8 ();
 
			info->spectators_on  = p->Recv_uint8 ();
 
			if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
 
				info->game_date    = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->start_date   = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			}
 
			while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
 
			info->map_width      = p->Recv_uint16();
 
			info->map_height     = p->Recv_uint16();
 
			info->landscape      = p->Recv_uint8 ();
 
			info->dedicated      = p->Recv_bool  ();
src/network/core/game_info.h
Show inline comments
 
@@ -31,75 +31,77 @@
 
 *                     - 16 bytes (sent sequentially) for the MD5 checksum
 
 *                       of the GRF
 
 *
 
 *   3+       4       current game date in days since 1-1-0 (DMY)
 
 *   3+       4       game introduction date in days since 1-1-0 (DMY)
 
 *
 
 *   2+       1       maximum number of companies allowed on the server
 
 *   2+       1       number of companies on the server
 
 *   2+       1       maximum number of spectators allowed on the server
 
 *
 
 *   1+       var     string with the name of the server
 
 *   1+       var     string with the revision of the server
 
 *   1+       1       the language run on the server
 
 *                    (0 = any, 1 = English, 2 = German, 3 = French)
 
 *   1+       1       whether the server uses a password (0 = no, 1 = yes)
 
 *   1+       1       maximum number of clients allowed on the server
 
 *   1+       1       number of clients on the server
 
 *   1+       1       number of spectators on the server
 
 *   1 & 2    2       current game date in days since 1-1-1920 (DMY)
 
 *   1 & 2    2       game introduction date in days since 1-1-1920 (DMY)
 
 *   1+       var     string with the name of the map
 
 *   1+       2       width of the map in tiles
 
 *   1+       2       height of the map in tiles
 
 *   1+       1       type of map:
 
 *                    (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);
 
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info);
 

	
 
#endif /* NETWORK_CORE_GAME_INFO_H */
src/network/network_gui.cpp
Show inline comments
 
@@ -630,96 +630,103 @@ public:
 

	
 
		/* Draw the right menu */
 
		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
 
		if (sel == nullptr) {
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
 
		} else if (!sel->online) {
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
 

	
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + detail_height + 4, STR_NETWORK_SERVER_LIST_SERVER_OFFLINE, TC_FROMSTRING, SA_HOR_CENTER); // server offline
 
		} else { // show game info
 

	
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name
 

	
 
			uint16 y = r.top + detail_height + 4;
 

	
 
			SetDParam(0, sel->info.clients_on);
 
			SetDParam(1, sel->info.clients_max);
 
			SetDParam(2, sel->info.companies_on);
 
			SetDParam(3, sel->info.companies_max);
 
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS);
 
			y += FONT_HEIGHT_NORMAL;
 

	
 
			SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.landscape);
 
			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
 
			case WID_NG_YEARS:   // Sort by years
 
			case WID_NG_INFO:    // Connectivity (green dot)
 
				if (this->servers.SortType() == widget - WID_NG_NAME) {
 
					this->servers.ToggleSortOrder();
 
					if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1;
 
				} else {
 
					this->servers.SetSortType(widget - WID_NG_NAME);
 
					this->servers.ForceResort();
 
					this->SortNetworkGameList();
 
				}
 
				this->ScrollToSelectedServer();
 
				this->SetDirty();
 
				break;
 

	
 
			case WID_NG_MATRIX: { // Show available network games
 
				uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX);
 
				this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr;
 
				this->list_pos = (server == nullptr) ? SLP_INVALID : id_v;
 
				this->SetDirty();
 

	
 
				/* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
 
				if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
 
				break;
 
			}
0 comments (0 inline, 0 general)