Skip to content

Commit

Permalink
Feature: join servers based on their invite code
Browse files Browse the repository at this point in the history
This removes the need to know a server IP to join it. Invite codes
are small (~7 characters) indentifiers for servers, which can be
exchanged with other players to join the servers.
  • Loading branch information
TrueBrain committed Jul 11, 2021
1 parent c6a759b commit 4eb5b81
Show file tree
Hide file tree
Showing 15 changed files with 417 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/console_cmds.cpp
Expand Up @@ -702,6 +702,7 @@ DEF_CONSOLE_CMD(ConServerInfo)
return true;
}

IConsolePrint(CC_DEFAULT, "Invite code: {}", _network_server_invite_code);
IConsolePrint(CC_DEFAULT, "Current/maximum clients: {:3d}/{:3d}", _network_game_info.clients_on, _settings_client.network.max_clients);
IConsolePrint(CC_DEFAULT, "Current/maximum companies: {:3d}/{:3d}", Company::GetNumItems(), _settings_client.network.max_companies);
IConsolePrint(CC_DEFAULT, "Current/maximum spectators: {:3d}/{:3d}", NetworkSpectatorCount(), _settings_client.network.max_spectators);
Expand Down
6 changes: 4 additions & 2 deletions src/lang/english.txt
Expand Up @@ -2045,12 +2045,12 @@ STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Search i
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 which will always be checked for running games
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_IP :{BLACK}Enter the address of the host
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
Expand Down Expand Up @@ -2136,6 +2136,8 @@ STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edit the
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name of the server
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibility
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing
STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE :{BLACK}Invite code
STR_NETWORK_CLIENT_LIST_SERVER_INVITE_CODE_TOOLTIP :{BLACK}Invite code other players can use to join this server
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE :{BLACK}Connection type
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP :{BLACK}Whether and how your server can be reached by others
STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Player
Expand Down
7 changes: 5 additions & 2 deletions src/network/core/config.h
Expand Up @@ -47,7 +47,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 = 4; ///< 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 = 1; ///< What version of game-coordinator-protocol do we use?
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'
Expand All @@ -67,7 +67,10 @@ static const uint NETWORK_CONTENT_VERSION_LENGTH = 16; ///< The m
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_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

Expand Down
6 changes: 5 additions & 1 deletion src/network/core/game_info.cpp
Expand Up @@ -141,7 +141,11 @@ void FillStaticNetworkServerGameInfo()
*/
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
{
/* Client_on is used as global variable to keep track on the number of clients. */
/* These variables are updated inside _network_game_info as if they are global variables:
* - clients_on
* - invite_code
* These don't need to be updated manually here.
*/
_network_game_info.companies_on = (byte)Company::GetNumItems();
_network_game_info.spectators_on = NetworkSpectatorCount();
_network_game_info.game_date = _date;
Expand Down
3 changes: 2 additions & 1 deletion src/network/core/tcp_connect.cpp
Expand Up @@ -13,6 +13,7 @@
#include "../../thread.h"

#include "tcp.h"
#include "../network_coordinator.h"
#include "../network_internal.h"

#include <deque>
Expand Down Expand Up @@ -47,7 +48,7 @@ TCPServerConnecter::TCPServerConnecter(const std::string &connection_string, uin
break;

case SERVER_ADDRESS_INVITE_CODE:
// TODO -- The next commit will add this functionality.
_network_coordinator_client.ConnectToServer(this->server_address.connection_string, this);
break;

default:
Expand Down
24 changes: 18 additions & 6 deletions src/network/core/tcp_coordinator.cpp
Expand Up @@ -27,12 +27,18 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p)
PacketCoordinatorType type = (PacketCoordinatorType)p->Recv_uint8();

switch (type) {
case PACKET_COORDINATOR_GC_ERROR: return this->Receive_GC_ERROR(p);
case PACKET_COORDINATOR_SERVER_REGISTER: return this->Receive_SERVER_REGISTER(p);
case PACKET_COORDINATOR_GC_REGISTER_ACK: return this->Receive_GC_REGISTER_ACK(p);
case PACKET_COORDINATOR_SERVER_UPDATE: return this->Receive_SERVER_UPDATE(p);
case PACKET_COORDINATOR_CLIENT_LISTING: return this->Receive_CLIENT_LISTING(p);
case PACKET_COORDINATOR_GC_LISTING: return this->Receive_GC_LISTING(p);
case PACKET_COORDINATOR_GC_ERROR: return this->Receive_GC_ERROR(p);
case PACKET_COORDINATOR_SERVER_REGISTER: return this->Receive_SERVER_REGISTER(p);
case PACKET_COORDINATOR_GC_REGISTER_ACK: return this->Receive_GC_REGISTER_ACK(p);
case PACKET_COORDINATOR_SERVER_UPDATE: return this->Receive_SERVER_UPDATE(p);
case PACKET_COORDINATOR_CLIENT_LISTING: return this->Receive_CLIENT_LISTING(p);
case PACKET_COORDINATOR_GC_LISTING: return this->Receive_GC_LISTING(p);
case PACKET_COORDINATOR_CLIENT_CONNECT: return this->Receive_CLIENT_CONNECT(p);
case PACKET_COORDINATOR_GC_CONNECTING: return this->Receive_GC_CONNECTING(p);
case PACKET_COORDINATOR_SERCLI_CONNECT_FAILED: return this->Receive_SERCLI_CONNECT_FAILED(p);
case PACKET_COORDINATOR_GC_CONNECT_FAILED: return this->Receive_GC_CONNECT_FAILED(p);
case PACKET_COORDINATOR_CLIENT_CONNECTED: return this->Receive_CLIENT_CONNECTED(p);
case PACKET_COORDINATOR_GC_DIRECT_CONNECT: return this->Receive_GC_DIRECT_CONNECT(p);

default:
Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type);
Expand Down Expand Up @@ -82,3 +88,9 @@ bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) { retur
bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); }
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); }
bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); }
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECT); }
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECTING); }
bool NetworkCoordinatorSocketHandler::Receive_SERCLI_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_CONNECT_FAILED); }
bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECT_FAILED); }
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECTED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECTED); }
bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_DIRECT_CONNECT); }
99 changes: 92 additions & 7 deletions src/network/core/tcp_coordinator.h
Expand Up @@ -23,15 +23,22 @@
* GC -> packets from Game Coordinator to either Client or Server.
* SERVER -> packets from Server to Game Coordinator.
* CLIENT -> packets from Client to Game Coordinator.
* SERCLI -> packets from either the Server or Client to Game Coordinator.
**/
enum PacketCoordinatorType {
PACKET_COORDINATOR_GC_ERROR, ///< Game Coordinator indicates there was an error.
PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration.
PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration.
PACKET_COORDINATOR_SERVER_UPDATE, ///< Server sends an set intervals an update of the server.
PACKET_COORDINATOR_CLIENT_LISTING, ///< Client is requesting a listing of all public servers.
PACKET_COORDINATOR_GC_LISTING, ///< Game Coordinator returns a listing of all public servers.
PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period).
PACKET_COORDINATOR_GC_ERROR, ///< Game Coordinator indicates there was an error.
PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration.
PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration.
PACKET_COORDINATOR_SERVER_UPDATE, ///< Server sends an set intervals an update of the server.
PACKET_COORDINATOR_CLIENT_LISTING, ///< Client is requesting a listing of all public servers.
PACKET_COORDINATOR_GC_LISTING, ///< Game Coordinator returns a listing of all public servers.
PACKET_COORDINATOR_CLIENT_CONNECT, ///< Client wants to connect to a server based on an invite code.
PACKET_COORDINATOR_GC_CONNECTING, ///< Game Coordinator informs the client of the token assigned to the connection attempt.
PACKET_COORDINATOR_SERCLI_CONNECT_FAILED, ///< Client/server tells the Game Coordinator the current connection attempt failed.
PACKET_COORDINATOR_GC_CONNECT_FAILED, ///< Game Coordinator informs client/server it has given up on the connection attempt.
PACKET_COORDINATOR_CLIENT_CONNECTED, ///< Client informs the Game Coordinator the connection with the server is established.
PACKET_COORDINATOR_GC_DIRECT_CONNECT, ///< Game Coordinator tells client to directly connect to the hostname:port of the server.
PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period)
};

/**
Expand All @@ -49,6 +56,7 @@ enum ConnectionType {
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.
};

/** Base socket handler for all Game Coordinator TCP sockets. */
Expand Down Expand Up @@ -76,6 +84,8 @@ class NetworkCoordinatorSocketHandler : public NetworkTCPSocketHandler {
* uint8 Game Coordinator protocol version.
* uint8 Type of game (see ServerGameType).
* uint16 Local port of the server.
* string Invite code the server wants to use (can be empty; coordinator will assign a new invite code).
* string Secret that belongs to the invite code (empty if invite code is empty).
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
Expand All @@ -85,6 +95,8 @@ class NetworkCoordinatorSocketHandler : public NetworkTCPSocketHandler {
/**
* Game Coordinator acknowledges the registration.
*
* string Invite code that can be used to join this server.
* string Secret that belongs to the invite code (only needed if reusing the invite code on next CLIENT_REGISTER).
* uint8 Type of connection was detected (see ConnectionType).
*
* @param p The packet that was just received.
Expand Down Expand Up @@ -130,6 +142,79 @@ class NetworkCoordinatorSocketHandler : public NetworkTCPSocketHandler {
*/
virtual bool Receive_GC_LISTING(Packet *p);

/**
* Client wants to connect to a Server.
*
* uint8 Game Coordinator protocol version.
* string Invite code of the Server to join.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_CLIENT_CONNECT(Packet *p);

/**
* Game Coordinator informs the Client under what token it will start the
* attempt to connect the Server and Client together.
*
* string Token to track the current connect request.
* string Invite code of the Server to join.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_GC_CONNECTING(Packet *p);

/**
* Client or Server failed to connect to the remote side.
*
* uint8 Game Coordinator protocol version.
* string Token to track the current connect request.
* uint8 Tracking number to track current connect request.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_SERCLI_CONNECT_FAILED(Packet *p);

/**
* Game Coordinator informs the Client that it failed to find a way to
* connect the Client to the Server. Any open connections for this token
* should be closed now.
*
* string Token to track the current connect request.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_GC_CONNECT_FAILED(Packet *p);

/**
* Client informs the Game Coordinator the connection with the Server is
* established. The Client will disconnect from the Game Coordinator next.
*
* uint8 Game Coordinator protocol version.
* string Token to track the current connect request.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_CLIENT_CONNECTED(Packet *p);

/**
* Game Coordinator requests that the Client makes a direct connection to
* the indicated peer, which is a Server.
*
* string Token to track the current connect request.
* uint8 Tracking number to track current connect request.
* string Hostname of the peer.
* uint16 Port of the peer.
*
* @param p The packet that was just received.
* @return True upon success, otherwise false.
*/
virtual bool Receive_GC_DIRECT_CONNECT(Packet *p);

bool HandlePacket(Packet *p);
public:
/**
Expand Down
10 changes: 7 additions & 3 deletions src/network/network.cpp
Expand Up @@ -589,9 +589,13 @@ void NetworkClose(bool close_admins)
ServerNetworkAdminSocketHandler::CloseListeners();

_network_coordinator_client.CloseConnection();
} else if (MyClient::my_client != nullptr) {
MyClient::SendQuit();
MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
} else {
if (MyClient::my_client != nullptr) {
MyClient::SendQuit();
MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
}

_network_coordinator_client.CloseAllTokens();
}

TCPConnecter::KillAll();
Expand Down

0 comments on commit 4eb5b81

Please sign in to comment.