Merge tag '12.0-beta2' into jgrpp-beta

# Conflicts:
#	docs/landscape_grid.html
#	src/lang/simplified_chinese.txt
#	src/network/network_server.cpp
#	src/station_cmd.cpp
This commit is contained in:
Jonathan G Rennison
2021-11-02 18:02:37 +00:00
32 changed files with 215 additions and 76 deletions

View File

@@ -51,7 +51,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe
static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use?
static const byte NETWORK_GAME_INFO_VERSION = 6; ///< 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 = 5; ///< What version of game-coordinator-protocol do we use?
static const byte NETWORK_COORDINATOR_VERSION = 6; ///< 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'

View File

@@ -61,9 +61,10 @@ enum ConnectionType {
* The type of error from the Game Coordinator.
*/
enum NetworkCoordinatorErrorType {
NETWORK_COORDINATOR_ERROR_UNKNOWN, ///< There was an unknown error.
NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED, ///< Your request for registration failed.
NETWORK_COORDINATOR_ERROR_INVALID_INVITE_CODE, ///< The invite code given is invalid.
NETWORK_COORDINATOR_ERROR_UNKNOWN, ///< There was an unknown error.
NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED, ///< Your request for registration failed.
NETWORK_COORDINATOR_ERROR_INVALID_INVITE_CODE, ///< The invite code given is invalid.
NETWORK_COORDINATOR_ERROR_REUSE_OF_INVITE_CODE, ///< The invite code is used by another (newer) server.
};
/** Base socket handler for all Game Coordinator TCP sockets. */

View File

@@ -135,8 +135,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
return false;
case NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED:
SetDParamStr(0, detail);
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED, STR_JUST_RAW_STRING, WL_ERROR);
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED, INVALID_STRING_ID, WL_ERROR);
/* To prevent that we constantly try to reconnect, switch to local game. */
_settings_client.network.server_game_type = SERVER_GAME_TYPE_LOCAL;
@@ -159,6 +158,15 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
return true;
}
case NETWORK_COORDINATOR_ERROR_REUSE_OF_INVITE_CODE:
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REUSE_OF_INVITE_CODE, INVALID_STRING_ID, WL_ERROR);
/* To prevent that we constantly battle for the same invite-code, switch to local game. */
_settings_client.network.server_game_type = SERVER_GAME_TYPE_LOCAL;
this->CloseConnection();
return false;
default:
DEBUG(net, 0, "Invalid error type %u received from Game Coordinator", error);
this->CloseConnection();
@@ -271,7 +279,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet *p)
}
/* Now store it based on the token. */
this->connecter[token] = connecter_pre_it->second;
this->connecter[token] = {invite_code, connecter_pre_it->second};
this->connecter_pre.erase(connecter_pre_it);
return true;
@@ -373,13 +381,20 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_TURN_CONNECT(Packet *p)
this->turn_handlers[token] = ClientNetworkTurnSocketHandler::Turn(token, tracking_number, ticket, connection_string);
if (!_network_server) {
auto connecter_it = this->connecter.find(token);
if (connecter_it == this->connecter.end()) {
/* Make sure we are still interested in connecting to this server. */
this->ConnectFailure(token, 0);
return true;
}
switch (_settings_client.network.use_relay_service) {
case URS_NEVER:
this->ConnectFailure(token, 0);
break;
case URS_ASK:
ShowNetworkAskRelay(connection_string, token);
ShowNetworkAskRelay(connecter_it->second.first, connection_string, token);
break;
case URS_ALLOW:
@@ -571,7 +586,7 @@ void ClientNetworkCoordinatorSocketHandler::ConnectSuccess(const std::string &to
* processes of connecting us. */
auto connecter_it = this->connecter.find(token);
if (connecter_it != this->connecter.end()) {
connecter_it->second->SetConnected(sock);
connecter_it->second.second->SetConnected(sock);
this->connecter.erase(connecter_it);
}
}
@@ -657,7 +672,7 @@ void ClientNetworkCoordinatorSocketHandler::CloseToken(const std::string &token)
/* Close the caller of the connection attempt. */
auto connecter_it = this->connecter.find(token);
if (connecter_it != this->connecter.end()) {
connecter_it->second->SetFailure();
connecter_it->second.second->SetFailure();
this->connecter.erase(connecter_it);
}
}
@@ -677,7 +692,7 @@ void ClientNetworkCoordinatorSocketHandler::CloseAllConnections()
for (auto &[token, it] : this->connecter) {
this->CloseStunHandler(token);
this->CloseTurnHandler(token);
it->SetFailure();
it.second->SetFailure();
/* Inform the Game Coordinator he can stop trying to connect us to the server. */
this->ConnectFailure(token, 0);

View File

@@ -54,7 +54,7 @@
class ClientNetworkCoordinatorSocketHandler : public NetworkCoordinatorSocketHandler {
private:
std::chrono::steady_clock::time_point next_update; ///< When to send the next update (if server and public).
std::map<std::string, TCPServerConnecter *> connecter; ///< Based on tokens, the current connecters that are pending.
std::map<std::string, std::pair<std::string, TCPServerConnecter *>> connecter; ///< Based on tokens, the current (invite-code, connecter) that are pending.
std::map<std::string, TCPServerConnecter *> connecter_pre; ///< Based on invite codes, the current connecters that are pending.
std::map<std::string, std::map<int, std::unique_ptr<ClientNetworkStunSocketHandler>>> stun_handlers; ///< All pending STUN handlers, stored by token:family.
std::map<std::string, std::unique_ptr<ClientNetworkTurnSocketHandler>> turn_handlers; ///< Pending TURN handler (if any), stored by token.

View File

@@ -2094,7 +2094,7 @@ public:
this->DrawCompany(c->index, r.left, r.right, r.top, line);
}
/* Specators */
/* Spectators */
this->DrawCompany(COMPANY_SPECTATOR, r.left, r.right, r.top, line);
break;
@@ -2376,13 +2376,18 @@ void ShowNetworkCompanyPasswordWindow(Window *parent)
}
/**
* Window used for asking the user if he is okay using a TURN server.
* Window used for asking the user if he is okay using a relay server.
*/
struct NetworkAskRelayWindow : public Window {
std::string connection_string; ///< The TURN server we want to connect to.
std::string token; ///< The token for this connection.
std::string server_connection_string; ///< The game server we want to connect to.
std::string relay_connection_string; ///< The relay server we want to connect to.
std::string token; ///< The token for this connection.
NetworkAskRelayWindow(WindowDesc *desc, Window *parent, const std::string &connection_string, const std::string &token) : Window(desc), connection_string(connection_string), token(token)
NetworkAskRelayWindow(WindowDesc *desc, Window *parent, const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token) :
Window(desc),
server_connection_string(server_connection_string),
relay_connection_string(relay_connection_string),
token(token)
{
this->parent = parent;
this->InitNested(0);
@@ -2415,7 +2420,8 @@ struct NetworkAskRelayWindow : public Window {
{
switch (widget) {
case WID_NAR_TEXT:
SetDParamStr(0, this->connection_string);
SetDParamStr(0, this->server_connection_string);
SetDParamStr(1, this->relay_connection_string);
break;
}
}
@@ -2466,13 +2472,14 @@ static WindowDesc _network_ask_relay_desc(
/**
* Show a modal confirmation window with "no" / "yes, once" / "yes, always" buttons.
* @param connection_string The relay server we want to connect to.
* @param server_connection_string The game server we want to connect to.
* @param relay_connection_string The relay server we want to connect to.
* @param token The token for this connection.
*/
void ShowNetworkAskRelay(const std::string &connection_string, const std::string &token)
void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token)
{
DeleteWindowByClass(WC_NETWORK_ASK_RELAY);
Window *parent = FindWindowById(WC_MAIN_WINDOW, 0);
new NetworkAskRelayWindow(&_network_ask_relay_desc, parent, connection_string, token);
new NetworkAskRelayWindow(&_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token);
}

View File

@@ -24,6 +24,7 @@ void ShowJoinStatusWindow();
void ShowNetworkGameWindow();
void ShowClientList();
void ShowNetworkCompanyPasswordWindow(Window *parent);
void ShowNetworkAskRelay(const std::string &server_connection_string, const std::string &relay_connection_string, const std::string &token);
/** Company information stored at the client side */
@@ -38,6 +39,5 @@ struct NetworkCompanyInfo : NetworkCompanyStats {
std::string clients; ///< The clients that control this company (Name1, name2, ..)
};
void ShowNetworkAskRelay(const std::string &connection_string, const std::string &token);
#endif /* NETWORK_GUI_H */

View File

@@ -1714,13 +1714,12 @@ static void NetworkAutoCleanCompanies()
bool NetworkMakeClientNameUnique(std::string &name)
{
bool is_name_unique = false;
uint number = 0;
std::string original_name = name;
while (!is_name_unique) {
for (uint number = 1; !is_name_unique && number <= MAX_CLIENTS; number++) { // Something's really wrong when there're more names than clients
is_name_unique = true;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
if (ci->client_name.compare(name) == 0) {
if (ci->client_name == name) {
/* Name already in use */
is_name_unique = false;
break;
@@ -1729,7 +1728,7 @@ bool NetworkMakeClientNameUnique(std::string &name)
/* Check if it is the same as the server-name */
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (ci != nullptr) {
if (ci->client_name.compare(name) == 0) is_name_unique = false; // name already in use
if (ci->client_name == name) is_name_unique = false; // name already in use
}
if (!is_name_unique) {
@@ -1833,10 +1832,10 @@ void NetworkServer_Tick(bool send_frame)
/* Client did still not report in within the specified limit. */
IConsolePrintF(CC_ERROR, cs->last_packet + std::chrono::milliseconds(lag * MILLISECONDS_PER_TICK) > std::chrono::steady_clock::now() ?
/* A packet was received in the last three game days, so the client is likely lagging behind. */
"Client #%d is dropped because the client's game state is more than %d ticks behind" :
"Client #%d (IP: %s) is dropped because the client's game state is more than %d ticks behind" :
/* No packet was received in the last three game days; sounds like a lost connection. */
"Client #%d is dropped because the client did not respond for more than %d ticks",
cs->client_id, lag);
"Client #%d (IP: %s) is dropped because the client did not respond for more than %d ticks",
cs->client_id, cs->GetClientIP(), lag);
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
continue;
}