Changeset - r25886:4a328504ff89
[Not reviewed]
master
0 9 0
Patric Stout - 3 years ago 2021-08-14 21:07:18
truebrain@openttd.org
Feature: make "join game" button join the game, instead of first showing a lobby window (#9467)

Nobody really paid attention to the lobby window, and it completely
missed its purpose. Most people don't even wait for companies to
show up, but just hit "New Company".
This in turn means people create a lot of unneeded companies, while
they "just want to watch the game" or join another company.

Instead, "Join Game" now just joins the game as spectators.
9 files changed with 4 insertions and 443 deletions:
0 comments (0 inline, 0 general)
src/lang/english.txt
Show inline comments
 
@@ -2083,37 +2083,12 @@ STR_NETWORK_START_SERVER_NUMBER_OF_COMPA
 
STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP            :{BLACK}Limit the server to a certain amount of companies
 
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
 

	
 
STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN                          :{BLACK}Preparing to join: {ORANGE}{RAW_STRING}
 
STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP                     :{BLACK}A list of all companies currently in this game. You can either join one or start a new one if there is a free company slot
 

	
 
STR_NETWORK_GAME_LOBBY_COMPANY_INFO                             :{SILVER}COMPANY INFO
 
STR_NETWORK_GAME_LOBBY_COMPANY_NAME                             :{SILVER}Company name: {WHITE}{RAW_STRING}
 
STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR                        :{SILVER}Inauguration: {WHITE}{NUM}
 
STR_NETWORK_GAME_LOBBY_VALUE                                    :{SILVER}Company value: {WHITE}{CURRENCY_LONG}
 
STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE                          :{SILVER}Current balance: {WHITE}{CURRENCY_LONG}
 
STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME                        :{SILVER}Last year's income: {WHITE}{CURRENCY_LONG}
 
STR_NETWORK_GAME_LOBBY_PERFORMANCE                              :{SILVER}Performance: {WHITE}{NUM}
 

	
 
STR_NETWORK_GAME_LOBBY_VEHICLES                                 :{SILVER}Vehicles: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE}
 
STR_NETWORK_GAME_LOBBY_STATIONS                                 :{SILVER}Stations: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE}
 
STR_NETWORK_GAME_LOBBY_PLAYERS                                  :{SILVER}Players: {WHITE}{RAW_STRING}
 

	
 
STR_NETWORK_GAME_LOBBY_NEW_COMPANY                              :{BLACK}New company
 
STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP                      :{BLACK}Create a new company
 
STR_NETWORK_GAME_LOBBY_SPECTATE_GAME                            :{BLACK}Spectate game
 
STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP                    :{BLACK}Watch the game as a spectator
 
STR_NETWORK_GAME_LOBBY_JOIN_COMPANY                             :{BLACK}Join company
 
STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP                     :{BLACK}Help manage this company
 

	
 
# Network connecting window
 
STR_NETWORK_CONNECTING_CAPTION                                  :{WHITE}Connecting...
 

	
 
############ Leave those lines in this order!!
 
STR_NETWORK_CONNECTING_1                                        :{BLACK}(1/6) Connecting...
 
STR_NETWORK_CONNECTING_2                                        :{BLACK}(2/6) Authorising...
src/network/core/tcp_game.h
Show inline comments
 
@@ -35,13 +35,13 @@ enum PacketGameType {
 
	PACKET_SERVER_BANNED,                ///< The server has banned you.
 

	
 
	/* Packets used by the client to join and an error message when the revision is wrong. */
 
	PACKET_CLIENT_JOIN,                  ///< The client telling the server it wants to join.
 
	PACKET_SERVER_ERROR,                 ///< Server sending an error message to the client.
 

	
 
	/* Packets used for the pre-game lobby. */
 
	/* Packets used for the pre-game lobby (unused, but remain for backward/forward compatibility). */
 
	PACKET_CLIENT_COMPANY_INFO,          ///< Request information about all companies.
 
	PACKET_SERVER_COMPANY_INFO,          ///< Information about a single company.
 

	
 
	/* Packets used to get the game info. */
 
	PACKET_SERVER_GAME_INFO,             ///< Information about the server.
 
	PACKET_CLIENT_GAME_INFO,             ///< Request information about the server.
src/network/network.cpp
Show inline comments
 
@@ -654,48 +654,12 @@ void NetworkQueryServer(const std::strin
 

	
 
	NetworkInitialize();
 

	
 
	new TCPQueryConnecter(connection_string);
 
}
 

	
 
/** Non blocking connection to query servers for their game and company info. */
 
class TCPLobbyQueryConnecter : TCPServerConnecter {
 
private:
 
	std::string connection_string;
 

	
 
public:
 
	TCPLobbyQueryConnecter(const std::string &connection_string) : TCPServerConnecter(connection_string, NETWORK_DEFAULT_PORT), connection_string(connection_string) {}
 

	
 
	void OnFailure() override
 
	{
 
		CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 

	
 
		ShowErrorMessage(STR_NETWORK_ERROR_NOCONNECTION, INVALID_STRING_ID, WL_ERROR);
 
	}
 

	
 
	void OnConnect(SOCKET s) override
 
	{
 
		_networking = true;
 
		new ClientNetworkGameSocketHandler(s, this->connection_string);
 
		MyClient::SendInformationQuery(true);
 
	}
 
};
 

	
 
/**
 
 * Query a server to fetch the game-info for the lobby.
 
 * @param connection_string the address to query.
 
 */
 
void NetworkQueryLobbyServer(const std::string &connection_string)
 
{
 
	if (!_network_available) return;
 

	
 
	NetworkInitialize();
 

	
 
	new TCPLobbyQueryConnecter(connection_string);
 
}
 

	
 
/**
 
 * Validates an address entered as a string and adds the server to
 
 * the list. If you use this function, the games will be marked
 
 * as manually added.
 
 * @param connection_string The IP:port of the server to add.
 
 * @param manually Whether the enter should be marked as manual added.
src/network/network_client.cpp
Show inline comments
 
@@ -566,73 +566,35 @@ NetworkRecvStatus ClientNetworkGameSocke
 
}
 

	
 
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p)
 
{
 
	if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_GAME_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 

	
 
	NetworkGameList *item = GetLobbyGameInfo();
 
	if (item == nullptr) {
 
		/* This is not the lobby, so add it to the game list. */
 
		item = NetworkGameListAddItem(this->connection_string);
 
	}
 
	NetworkGameList *item = NetworkGameListAddItem(this->connection_string);
 

	
 
	/* Clear any existing GRFConfig chain. */
 
	ClearGRFConfigList(&item->info.grfconfig);
 
	/* Retrieve the NetworkGameInfo from the packet. */
 
	DeserializeNetworkGameInfo(p, &item->info);
 
	/* Check for compatability with the client. */
 
	CheckGameCompatibility(item->info);
 
	/* Ensure we consider the server online. */
 
	item->online = true;
 

	
 
	/* It could be either window, but only one is open, so redraw both. */
 
	UpdateNetworkGameWindow();
 
	SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 

	
 
	/* We will receive company info next, so keep connection open. */
 
	if (this->status == STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_OKAY;
 
	return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
}
 

	
 
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p)
 
{
 
	if (this->status != STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 

	
 
	byte company_info_version = p->Recv_uint8();
 

	
 
	if (!this->HasClientQuit() && company_info_version == NETWORK_COMPANY_INFO_VERSION) {
 
		/* We have received all data... (there are no more packets coming) */
 
		if (!p->Recv_bool()) return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		CompanyID current = (Owner)p->Recv_uint8();
 
		if (current >= MAX_COMPANIES) return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		NetworkCompanyInfo *company_info = GetLobbyCompanyInfo(current);
 
		if (company_info == nullptr) return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		company_info->company_name = p->Recv_string(NETWORK_COMPANY_NAME_LENGTH);
 
		company_info->inaugurated_year = p->Recv_uint32();
 
		company_info->company_value    = p->Recv_uint64();
 
		company_info->money            = p->Recv_uint64();
 
		company_info->income           = p->Recv_uint64();
 
		company_info->performance      = p->Recv_uint16();
 
		company_info->use_password     = p->Recv_bool();
 
		for (uint i = 0; i < NETWORK_VEH_END; i++) {
 
			company_info->num_vehicle[i] = p->Recv_uint16();
 
		}
 
		for (uint i = 0; i < NETWORK_VEH_END; i++) {
 
			company_info->num_station[i] = p->Recv_uint16();
 
		}
 
		company_info->ai               = p->Recv_bool();
 

	
 
		company_info->clients = p->Recv_string(NETWORK_CLIENTS_LENGTH);
 

	
 
		SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 

	
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 
	/* Unused, but this packet is part of the "this will never change" packet group. */
 

	
 
	return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
}
 

	
 
/* This packet contains info about the client (playas and name)
 
 *  as client we save this in NetworkClientInfo, linked via 'client_id'
src/network/network_gui.cpp
Show inline comments
 
@@ -50,13 +50,12 @@
 

	
 
#include <map>
 

	
 
#include "../safeguards.h"
 

	
 
static void ShowNetworkStartServerWindow();
 
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
 

	
 
static const int NETWORK_LIST_REFRESH_DELAY = 30; ///< Time, in seconds, between updates of the network list.
 

	
 
static ClientID _admin_client_id = INVALID_CLIENT_ID; ///< For what client a confirmation window is open.
 
static CompanyID _admin_company_id = INVALID_COMPANY; ///< For what company a confirmation window is open.
 

	
 
@@ -767,13 +766,13 @@ public:
 
			case WID_NG_START: // Start server
 
				ShowNetworkStartServerWindow();
 
				break;
 

	
 
			case WID_NG_JOIN: // Join Game
 
				if (this->server != nullptr) {
 
					ShowNetworkLobbyWindow(this->server);
 
					NetworkClientConnectGame(this->server->connection_string, COMPANY_SPECTATOR);
 
				}
 
				break;
 

	
 
			case WID_NG_REFRESH: // Refresh
 
				if (this->server != nullptr) NetworkQueryServer(this->server->connection_string);
 
				break;
 
@@ -987,13 +986,12 @@ static WindowDesc _network_game_window_d
 
	_nested_network_game_widgets, lengthof(_nested_network_game_widgets)
 
);
 

	
 
void ShowNetworkGameWindow()
 
{
 
	static bool first = true;
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
 

	
 
	/* Only show once */
 
	if (first) {
 
		first = false;
 
		/* Add all servers from the config file to our list. */
 
@@ -1263,334 +1261,16 @@ static WindowDesc _network_start_server_
 

	
 
static void ShowNetworkStartServerWindow()
 
{
 
	if (!NetworkValidateOurClientName()) return;
 

	
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
 

	
 
	new NetworkStartServerWindow(&_network_start_server_window_desc);
 
}
 

	
 
struct NetworkLobbyWindow : public Window {
 
	CompanyID company;       ///< Selected company
 
	NetworkGameList *server; ///< Selected server
 
	NetworkCompanyInfo company_info[MAX_COMPANIES];
 
	Scrollbar *vscroll;
 

	
 
	NetworkLobbyWindow(WindowDesc *desc, NetworkGameList *ngl) :
 
			Window(desc), company(INVALID_COMPANY), server(ngl)
 
	{
 
		this->CreateNestedTree();
 
		this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR);
 
		this->FinishInitNested(WN_NETWORK_WINDOW_LOBBY);
 
	}
 

	
 
	CompanyID NetworkLobbyFindCompanyIndex(byte pos) const
 
	{
 
		/* Scroll through all this->company_info and get the 'pos' item that is not empty. */
 
		for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
 
			if (!this->company_info[i].company_name.empty()) {
 
				if (pos-- == 0) return i;
 
			}
 
		}
 

	
 
		return COMPANY_FIRST;
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		switch (widget) {
 
			case WID_NL_HEADER:
 
				size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
 
				break;
 

	
 
			case WID_NL_MATRIX:
 
				resize->height = WD_MATRIX_TOP + std::max<uint>(std::max(GetSpriteSize(SPR_LOCK).height, GetSpriteSize(SPR_PROFIT_LOT).height), FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM;
 
				size->height = 10 * resize->height;
 
				break;
 

	
 
			case WID_NL_DETAILS:
 
				size->height = 30 + 11 * FONT_HEIGHT_NORMAL;
 
				break;
 
		}
 
	}
 

	
 
	void SetStringParameters(int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_NL_TEXT:
 
				SetDParamStr(0, this->server->info.server_name);
 
				break;
 
		}
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_NL_DETAILS:
 
				this->DrawDetails(r);
 
				break;
 

	
 
			case WID_NL_MATRIX:
 
				this->DrawMatrix(r);
 
				break;
 
		}
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		const NetworkGameInfo *gi = &this->server->info;
 

	
 
		/* Join button is disabled when no company is selected and for AI companies. */
 
		this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai);
 
		/* Cannot start new company if there are too many. */
 
		this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max);
 

	
 
		this->vscroll->SetCount(gi->companies_on);
 

	
 
		/* Draw window widgets */
 
		this->DrawWidgets();
 
	}
 

	
 
	void DrawMatrix(const Rect &r) const
 
	{
 
		bool rtl = _current_text_dir == TD_RTL;
 
		uint left = r.left + WD_FRAMERECT_LEFT;
 
		uint right = r.right - WD_FRAMERECT_RIGHT;
 
		uint text_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - FONT_HEIGHT_NORMAL) / 2 + WD_MATRIX_TOP;
 

	
 
		Dimension lock_size = GetSpriteSize(SPR_LOCK);
 
		int lock_width      = lock_size.width;
 
		int lock_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2 + WD_MATRIX_TOP;
 

	
 
		Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT);
 
		int profit_width      = lock_size.width;
 
		int profit_y_offset   = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2 + WD_MATRIX_TOP;
 

	
 
		uint text_left   = left  + (rtl ? lock_width + profit_width + 4 : 0);
 
		uint text_right  = right - (rtl ? 0 : lock_width + profit_width + 4);
 
		uint profit_left = rtl ? left : right - profit_width;
 
		uint lock_left   = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2;
 

	
 
		int y = r.top;
 
		/* Draw company list */
 
		int pos = this->vscroll->GetPosition();
 
		while (pos < this->server->info.companies_on) {
 
			byte company = NetworkLobbyFindCompanyIndex(pos);
 
			bool income = false;
 
			if (this->company == company) {
 
				GfxFillRect(r.left + WD_BEVEL_LEFT, y + 1, r.right - WD_BEVEL_RIGHT, y + this->resize.step_height - 2, PC_GREY);  // show highlighted item with a different colour
 
			}
 

	
 
			DrawString(text_left, text_right, y + text_offset, this->company_info[company].company_name, TC_BLACK);
 
			if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset);
 

	
 
			/* If the company's income was positive puts a green dot else a red dot */
 
			if (this->company_info[company].income >= 0) income = true;
 
			DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset);
 

	
 
			pos++;
 
			y += this->resize.step_height;
 
			if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break;
 
		}
 
	}
 

	
 
	void DrawDetails(const Rect &r) const
 
	{
 
		const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12;
 
		/* Draw info about selected company when it is selected in the left window. */
 
		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_HOR_CENTER);
 

	
 
		if (this->company == INVALID_COMPANY || this->company_info[this->company].company_name.empty()) return;
 

	
 
		int y = r.top + detail_height + 4;
 
		const NetworkGameInfo *gi = &this->server->info;
 

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

	
 
		SetDParamStr(0, this->company_info[this->company].company_name);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].inaugurated_year);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].company_value);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].money);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].income);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].performance);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]);
 
		SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]);
 
		SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]);
 
		SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]);
 
		SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]);
 
		SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]);
 
		SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]);
 
		SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]);
 
		SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		SetDParamStr(0, this->company_info[this->company].clients);
 
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_NL_CANCEL:   // Cancel button
 
				ShowNetworkGameWindow();
 
				break;
 

	
 
			case WID_NL_MATRIX: { // Company list
 
				uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX);
 
				this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(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_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1);
 
				break;
 
			}
 

	
 
			case WID_NL_JOIN:     // Join company
 
				/* Button can be clicked only when it is enabled. */
 
				NetworkClientConnectGame(this->server->connection_string, this->company);
 
				break;
 

	
 
			case WID_NL_NEW:      // New company
 
				NetworkClientConnectGame(this->server->connection_string, COMPANY_NEW_COMPANY);
 
				break;
 

	
 
			case WID_NL_SPECTATE: // Spectate game
 
				NetworkClientConnectGame(this->server->connection_string, COMPANY_SPECTATOR);
 
				break;
 

	
 
			case WID_NL_REFRESH:  // Refresh
 
				/* Clear the information so removed companies don't remain */
 
				for (auto &company : this->company_info) company = {};
 

	
 
				NetworkQueryLobbyServer(this->server->connection_string);
 
				break;
 
		}
 
	}
 

	
 
	void OnResize() override
 
	{
 
		this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX);
 
	}
 
};
 

	
 
static const NWidgetPart _nested_network_lobby_window_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
 
		NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND),
 
		NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NL_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 3),
 
		NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10),
 
			/* Company list. */
 
			NWidget(NWID_VERTICAL),
 
				NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(),
 
				NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NL_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP), SetScrollbar(WID_NL_SCROLLBAR),
 
			EndContainer(),
 
			NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR),
 
			NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetResize(0, 1),
 
			/* Company info. */
 
			NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(),
 
		EndContainer(),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 9),
 
		/* Buttons. */
 
		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 3, 10),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP),
 
			EndContainer(),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP),
 
			EndContainer(),
 
			NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0),
 
				NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
 
				NWidget(NWID_SPACER), SetFill(1, 1),
 
			EndContainer(),
 
		EndContainer(),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 8),
 
	EndContainer(),
 
};
 

	
 
static WindowDesc _network_lobby_window_desc(
 
	WDP_CENTER, nullptr, 0, 0,
 
	WC_NETWORK_WINDOW, WC_NONE,
 
	0,
 
	_nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets)
 
);
 

	
 
/**
 
 * Show the networklobbywindow with the selected server.
 
 * @param ngl Selected game pointer which is passed to the new window.
 
 */
 
static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
 
{
 
	if (!NetworkValidateOurClientName()) return;
 

	
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
 
	CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
 

	
 
	_settings_client.network.last_joined = ngl->connection_string;
 

	
 
	NetworkQueryLobbyServer(ngl->connection_string);
 

	
 
	new NetworkLobbyWindow(&_network_lobby_window_desc, ngl);
 
}
 

	
 
/**
 
 * Get the company information of a given company to fill for the lobby.
 
 * @param company the company to get the company info struct from.
 
 * @return the company info struct to write the (downloaded) data to.
 
 */
 
NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
 
{
 
	NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow*>(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY));
 
	return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr;
 
}
 

	
 
/**
 
 * Get the game information for the lobby.
 
 * @return the game info struct to write the (downloaded) data to.
 
 */
 
NetworkGameList *GetLobbyGameInfo()
 
{
 
	NetworkLobbyWindow *lobby = dynamic_cast<NetworkLobbyWindow *>(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY));
 
	return lobby != nullptr ? lobby->server : nullptr;
 
}
 

	
 
/* The window below gives information about the connected clients
 
 * and also makes able to kick them (if server) and stuff like that. */
 

	
 
extern void DrawCompanyIcon(CompanyID cid, int x, int y);
 

	
 
static const NWidgetPart _nested_client_list_widgets[] = {
src/network/network_gui.h
Show inline comments
 
@@ -34,11 +34,9 @@ struct NetworkCompanyInfo : NetworkCompa
 
	Money income;             ///< How much did the company earn last year
 
	uint16 performance;       ///< What was his performance last month?
 
	bool use_password;        ///< Is there a password
 
	std::string clients;      ///< The clients that control this company (Name1, name2, ..)
 
};
 

	
 
NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company);
 
NetworkGameList *GetLobbyGameInfo();
 
void ShowNetworkAskRelay(const std::string &connection_string, const std::string &token);
 

	
 
#endif /* NETWORK_GUI_H */
src/network/network_internal.h
Show inline comments
 
@@ -91,13 +91,12 @@ extern std::string _network_server_name;
 

	
 
extern uint8 _network_reconnect;
 

	
 
extern CompanyMask _network_company_passworded;
 

	
 
void NetworkQueryServer(const std::string &connection_string);
 
void NetworkQueryLobbyServer(const std::string &connection_string);
 

	
 
void GetBindAddresses(NetworkAddressList *addresses, uint16 port);
 
struct NetworkGameList *NetworkAddServer(const std::string &connection_string, bool manually = true, bool never_expire = false);
 
void NetworkRebuildHostList();
 
void UpdateNetworkGameWindow();
 

	
src/widgets/network_widget.h
Show inline comments
 
@@ -72,27 +72,12 @@ enum NetworkStartServerWidgets {
 
	WID_NSS_PLAY_SCENARIO,     ///< Play scenario button.
 
	WID_NSS_PLAY_HEIGHTMAP,    ///< Play heightmap button.
 

	
 
	WID_NSS_CANCEL,            ///< 'Cancel' button.
 
};
 

	
 
/** Widgets of the #NetworkLobbyWindow class. */
 
enum NetworkLobbyWidgets {
 
	WID_NL_BACKGROUND, ///< Background of the window.
 
	WID_NL_TEXT,       ///< Heading text.
 
	WID_NL_HEADER,     ///< Header above list of companies.
 
	WID_NL_MATRIX,     ///< List of companies.
 
	WID_NL_SCROLLBAR,  ///< Scroll bar.
 
	WID_NL_DETAILS,    ///< Company details.
 
	WID_NL_JOIN,       ///< 'Join company' button.
 
	WID_NL_NEW,        ///< 'New company' button.
 
	WID_NL_SPECTATE,   ///< 'Spectate game' button.
 
	WID_NL_REFRESH,    ///< 'Refresh server' button.
 
	WID_NL_CANCEL,     ///< 'Cancel' button.
 
};
 

	
 
/** Widgets of the #NetworkClientListWindow class. */
 
enum ClientListWidgets {
 
	WID_CL_PANEL,                      ///< Panel of the window.
 
	WID_CL_SERVER_SELECTOR,            ///< Selector to hide the server frame.
 
	WID_CL_SERVER_NAME,                ///< Server name.
 
	WID_CL_SERVER_NAME_EDIT,           ///< Edit button for server name.
src/window_type.h
Show inline comments
 
@@ -22,13 +22,12 @@ enum WindowNumberEnum {
 
	WN_QUERY_STRING_SIGN, ///< Query string for signs.
 

	
 
	WN_CONFIRM_POPUP_QUERY = 0,       ///< Query popup confirm.
 
	WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, ///< Query popup confirm for bootstrap.
 

	
 
	WN_NETWORK_WINDOW_GAME = 0,     ///< Network game window.
 
	WN_NETWORK_WINDOW_LOBBY,        ///< Network lobby window.
 
	WN_NETWORK_WINDOW_CONTENT_LIST, ///< Network content list.
 
	WN_NETWORK_WINDOW_START,        ///< Network start server.
 

	
 
	WN_NETWORK_STATUS_WINDOW_JOIN = 0,         ///< Network join status.
 
	WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, ///< Network content download status.
 
};
 
@@ -456,13 +455,12 @@ enum WindowClass {
 
	WC_MODAL_PROGRESS,
 

	
 

	
 
	/**
 
	 * Network window; %Window numbers:
 
	 *   - #WN_NETWORK_WINDOW_GAME = #NetworkGameWidgets
 
	 *   - #WN_NETWORK_WINDOW_LOBBY = #NetworkLobbyWidgets
 
	 *   - #WN_NETWORK_WINDOW_CONTENT_LIST = #NetworkContentListWidgets
 
	 *   - #WN_NETWORK_WINDOW_START = #NetworkStartServerWidgets
 
	 */
 
	WC_NETWORK_WINDOW,
 

	
 
	/**
0 comments (0 inline, 0 general)