Feature: join servers based on their invite code

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.
This commit is contained in:
Patric Stout
2021-04-29 15:37:02 +02:00
committed by Patric Stout
parent 1baec41542
commit e4d216e44b
15 changed files with 422 additions and 29 deletions

View File

@@ -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'
@@ -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

View File

@@ -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;

View File

@@ -13,6 +13,7 @@
#include "../../thread.h"
#include "tcp.h"
#include "../network_coordinator.h"
#include "../network_internal.h"
#include <deque>
@@ -48,8 +49,7 @@ TCPServerConnecter::TCPServerConnecter(const std::string &connection_string, uin
case SERVER_ADDRESS_INVITE_CODE:
this->status = Status::CONNECTING;
// TODO -- The next commit will add this functionality.
_network_coordinator_client.ConnectToServer(this->server_address.connection_string, this);
break;
default:

View File

@@ -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);
@@ -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); }

View File

@@ -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)
};
/**
@@ -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. */
@@ -76,6 +84,8 @@ protected:
* 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.
@@ -85,6 +95,8 @@ protected:
/**
* 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 SERVER_REGISTER).
* uint8 Type of connection was detected (see ConnectionType).
*
* @param p The packet that was just received.
@@ -130,6 +142,79 @@ protected:
*/
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:
/**