CUGL 2.5
Cornell University Game Library
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Friends | List of all members
cugl::net::NetcodeConnection Class Reference

#include <CUNetcodeConnection.h>

Inheritance diagram for cugl::net::NetcodeConnection:

Public Types

enum class  State : int {
  INACTIVE = -1 , CONNECTING = 0 , NEGOTIATING = 1 , CONNECTED = 2 ,
  INSESSION = 3 , MIGRATING = 4 , DISCONNECTED = 5 , DENIED = 6 ,
  MISMATCHED = 7 , INVALID = 8 , FAILED = 9 , DISPOSED = 10
}
 
typedef std::function< void(const std::string uuid)> ConnectionCallback
 
typedef std::function< bool(bool confirmed)> PromotionCallback
 
typedef std::function< void(State state)> StateCallback
 
typedef std::function< void(const std::string source, const std::vector< std::byte > &message)> Dispatcher
 

Public Member Functions

 NetcodeConnection ()
 
 ~NetcodeConnection ()
 
std::string getUUID ()
 
bool isHost () const
 
const std::string getHost ()
 
bool isOpen () const
 
State getState () const
 
size_t getCapacity ()
 
void setCapacity (size_t capacity)
 
const std::string getRoom () const
 
const std::unordered_set< std::string > getPlayers ()
 
const std::unordered_map< std::string, std::shared_ptr< NetcodePeer > > getPeers ()
 
bool isPlayerActive (const std::string player)
 
size_t getNumPlayers ()
 
size_t getTotalPlayers ()
 
void open ()
 
void close ()
 
bool sendTo (const std::string dst, const std::vector< std::byte > &data)
 
bool sendToHost (const std::vector< std::byte > &data)
 
bool broadcast (const std::vector< std::byte > &data)
 
void receive (const Dispatcher &dispatcher)
 
void startSession ()
 
void endSession ()
 
void onReceipt (Dispatcher callback)
 
void onConnect (ConnectionCallback callback)
 
void onDisconnect (ConnectionCallback callback)
 
void onStateChange (StateCallback callback)
 
void onPromotion (PromotionCallback callback)
 
void setDebug (bool flag)
 
bool getDebug () const
 

Static Public Member Functions

static std::shared_ptr< NetcodeConnectionalloc (const NetcodeConfig &config)
 
static std::shared_ptr< NetcodeConnectionalloc (const NetcodeConfig &config, const std::string room)
 

Friends

class NetcodeManager
 
class NetcodeChannel
 
class NetcodePeer
 

Detailed Description

This class to supports a connection to other players with a peer-to-peer interface.

The premise of this class is to make networking as simple as possible. Simply call broadcast with a byte vector, and then all others will receive it when they call receive. You can use the classes NetcodeSerializer and NetcodeDeserializer to handle more complex types.

This class maintains a networked game using a peer-to-peer connections. One player is designated as "host", but this is purely an organizational concept. The host monitors the other players, allowing them join. But once the game starts, all communication is peer-to-peer and the question of authority are determined by the application layer.

You can use this as a true client-server by replacing all calls to broadcast with calls to sendTo. That way clients can send to the host and the host can broadcast its responses.

Using this class requires an external lobby websocket server to enable Web RTC data channels. This server does not handle actual game data. In only connects that players, an occasionally monitors for disconnects requiring host migration. This reduces server costs significantly. We will provide you a Docker package for a lobby server later in the semester.

This class supports optional host migration should the host be lost. Upon loss of the host, each surviving client will receive an invocation of the callback function onPromotion. if the callback exists and returns true, that client will become a candidate to be the new host. If more than one client is a candidate, the lobby will chose the first available. If any client disconnects during the migration process, host migration will fail. See onPromotion for more details.

It is completely unsafe for network connections to be used on the stack. For that reason, this class hides the initialization methods (and the constructors create uninitialized connections). You are forced to go through the static allocator alloc to create instances of this class.

Member Typedef Documentation

◆ ConnectionCallback

This type represents a callback for the NetcodeConnection class.

This type refers to two different possible callbacks: one when a new peer connection connects and another when it disconnects. This notification goes to all connections, whether they are host or client (so there is no guarantee of a direct connection to the peer). The uuid sent to the callback indentifies the peer that connected/disconnected.

Callback functions differ from listeners (found in the input classes) in that only one callback of any type is allowed in a NetcodeConnection class. Callback functions are guaranteed to be called at the start of an animation frame, before the method Application#update(float).

The function type is equivalent to

 std::function<void(const std::string uuid)>
Parameters
uuidThe unique identifier of the disconnecting peer

◆ Dispatcher

The dispatcher is called by the receive function to consume data from the message buffer. Not only does it relay the message data, but it also communicates the "source". For broadcast messages, this will be the value "broadcast". For private messages, it will be the UUID of the sending client. Note that only the host can receive private messages.

The function type is equivalent to

 const std::function<void(const std::string source,
                          const std::vector<std::byte>& message)>
Parameters
sourceThe message source
messageThe message data

◆ PromotionCallback

This type represents a callback for the NetcodeConnection class.

This callback is invoked when the websocket makes an offer to this connection to become host, as part of host migration. If the callback returns true, then this connection will become a candidate for the new host. However, selection is not guaranteed, as the server polls all clients simultaneously.

If the connection is actually selected as the new host, this callback will be invoked a second time with the parameter set to true. If the callback returns false on the confirmation (because of a change of heart), migration fails and all clients are disconnected.

Callback functions differ from listeners (found in the input classes) in that only one callback of any type is allowed in a NetcodeConnection class. Callback functions are guaranteed to be called at the start of an animation frame, before the method Application#update(float).

The function type is equivalent to

 std::function<bool(bool)>
Parameters
confirmedWhether this connection is confirmed as the new host
Returns
true if this connection is willing to become host

◆ StateCallback

This type represents a callback for the NetcodeConnection class.

This callback is invoked when the connection state has changed. The parameter marks the new connection state of the migration. This is particularly helpful for monitoring host migrations.

Callback functions differ from listeners (found in the input classes) in that only one callback of any type is allowed in a NetcodeConnection class. Callback functions are guaranteed to be called at the start of an animation frame, before the method Application#update(float).

The function type is equivalent to

 std::function<void(State state)>
Parameters
stateThe new connection state

Member Enumeration Documentation

◆ State

enum class cugl::net::NetcodeConnection::State : int
strong

An enum representing the current connection state.

This state is the relationship of this connection to the lobby websocket server. The peer connections and data channels have their own separate states.

Enumerator
INACTIVE 

The connection is initialized, but open has not yet been called.

CONNECTING 

The connection is in the initial connection phase.

This represent the initial handshake with the game lobby server. This state ends when the connection is officially marked as open.

NEGOTIATING 

The connection is negotiating its role with the server (host or client)

This state ends when the connection receives a role acknowledgement from the server.

CONNECTED 

The connection is complete and currently allowing players to join the room.

This state ends when connection receives an acknowledgement that the host called the method startSession. At which point it will transition to INSESSION.

INSESSION 

The connection is actively playing the game.

This states ends when the player closes the connection or destroys the socket.

MIGRATING 

The connection is migrating to a new host.

This state is caused when the host connection does not end "cleanly" (e.g. with a call to close. No messages can be sent during this state.

DISCONNECTED 

The connection is disconnected.

This state occurs when the connection to the websocket is lost. It is typically the result of a call to close.

DENIED 

The connection was denied the option to join a room.

This error indicates that the room is full, or the game has started.

MISMATCHED 

The connection did not match the host API version

INVALID 

The client connection specified a non-existent room

FAILED 

The connection failed with an unknown error.

DISPOSED 

This object has been disposed and is no longer available for use.

Constructor & Destructor Documentation

◆ NetcodeConnection()

cugl::net::NetcodeConnection::NetcodeConnection ( )

Creates a degenerate websocket connection.

This object has not been initialized with a NetcodeConfig and cannot be used.

You should NEVER USE THIS CONSTRUCTOR. All connections should be created by the static constructor alloc instead.

◆ ~NetcodeConnection()

cugl::net::NetcodeConnection::~NetcodeConnection ( )

Deletes this websocket connection, disposing all resources

Member Function Documentation

◆ alloc() [1/2]

static std::shared_ptr< NetcodeConnection > cugl::net::NetcodeConnection::alloc ( const NetcodeConfig config)
inlinestatic

Returns a newly allocated network connection as host.

This method initializes this websocket connection with all of the correct settings. However, it does not connect to the game lobby. You must call the method open to initiate connection. This design decision is intended to give the user a chance to set the callback functions before connection is established.

This method will always return nullptr if the NetworkLayer failed to initialize.

Parameters
configThe connection configuration
Returns
a newly allocated network connection as host.

◆ alloc() [2/2]

static std::shared_ptr< NetcodeConnection > cugl::net::NetcodeConnection::alloc ( const NetcodeConfig config,
const std::string  room 
)
inlinestatic

Returns a newly allocated network connection as a client.

This method initializes this websocket connection with all of the correct settings. However, it does not connect to the game lobby. You must call the method open to initiate connection. This design decision is intended to give the user a chance to set the callback functions before connection is established.

The room should match one specified by the host. If you are using the traditional CUGL lobby server, this will be a hexadecimal string.

This method will always return nullptr if the NetworkLayer failed to initialize.

Parameters
configThe connection configuration
roomThe host's assigned room id
Returns
a newly allocated network connection as a client.

◆ broadcast()

bool cugl::net::NetcodeConnection::broadcast ( const std::vector< std::byte > &  data)

Sends a byte array to all other players.

Within a few frames, other players should receive this via a call to receive or the callback function onReceipt. As this is a broadcast message, this player will receive it as well (with the indication of this connection as the sender).

As with sendTo, communication from a particular source is guaranteed to be ordered. So if connection A broadcasts two messages, all other connections will receive those messages in the same order. However, there is no relationship between the messages coming from different sources.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires a connection be established. Otherwise it will return false. It will also return false if the host is currently migrating.

Parameters
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ close()

void cugl::net::NetcodeConnection::close ( )

Closes this connection normally.

If this method is called on a client, it simply leaves the game; the game can continue without this. If the method is called on the host, shutdown commands are issued to all of the clients. Host migration will never take place when this method is called. Migration requires that the host disconnect without first closing.

Because this requires coordination with this connection, this method does not close the connection immediately. Verify that the state is State#DISCONNECTED before destroying this object.

◆ endSession()

void cugl::net::NetcodeConnection::endSession ( )

Marks the game as completed.

This will issue shutdown commands to call clients, disconnecting them from the game.

Note: This can only be called by the host. This method is ignored for clients.

◆ getCapacity()

size_t cugl::net::NetcodeConnection::getCapacity ( )

Returns the message buffer capacity.

It is possible for this connection to receive several messages over the network before it has a chance to all receive. This buffer stores those messages to be read later. The capacity indicates the number of messages that can be stored.

Note that this is NOT the same as the capacity of a single message. That value was set as part of the initial NetcodeConfig.

This method is not const because it requires a lock.

Returns
the message buffer capacity.

◆ getDebug()

bool cugl::net::NetcodeConnection::getDebug ( ) const
inline

Returns the debugging status of this connection.

If debugging is active, connections will be quite verbose

Returns
the debugging status of this connection.

◆ getHost()

const std::string cugl::net::NetcodeConnection::getHost ( )

Returns the UUID for the (current) game host

This method is not const because it requires a lock.

Returns
the UUID for the (current) game host

◆ getNumPlayers()

size_t cugl::net::NetcodeConnection::getNumPlayers ( )

Returns the number of players currently connected to this game

This does not include any players that have been disconnected.

This method is not const because it requires a lock.

Returns
the number of players currently connected to this game

◆ getPeers()

const std::unordered_map< std::string, std::shared_ptr< NetcodePeer > > cugl::net::NetcodeConnection::getPeers ( )

Returns the list of peer connections for this websocket connection

If the connection is a client, there will only be one peer (the host). Otherwise, this list contains all the peer connections to the clients. Most users should never need this method, as all communication should be initiated through the websocket. It is provided for debugging purposes only.

This method is not const because it requires a lock.

Returns
the list of peer connections for this websocket connection

◆ getPlayers()

const std::unordered_set< std::string > cugl::net::NetcodeConnection::getPlayers ( )

Returns the list of active players

This vector stores the UUIDs of all the players who are currently playing the game. This list will continually update as players join and leave the game.

This method is not const because it requires a lock.

Returns
the list of active players

◆ getRoom()

const std::string cugl::net::NetcodeConnection::getRoom ( ) const
inline

Returns the room ID or empty string.

If this player is a client, this will return the room ID this object was constructed with. Otherwise, as host, this will return the empty string until getState is CONNECTED.

If this connection is used with the standard CUGL lobby server, then the string will represent a hexadecimal number.

Returns
the room ID or empty string.

◆ getState()

State cugl::net::NetcodeConnection::getState ( ) const
inline

Returns the current state of this connection.

Monitoring state is one of the most important components of working with a NetcodeConnection. Many state changes (moving from State#CONNECTED to State#INSESSION, or State#INSESSION to State#MIGRATING) can happen due to circumstances beyond the control of this connection. It is particularly important to pay attention to the State#MIGRATING state, as no messages can be sent during that time.

State can either be monitored via polling with this method, or with a callback set to onStateChange.

◆ getTotalPlayers()

size_t cugl::net::NetcodeConnection::getTotalPlayers ( )

Returns the number of players present when the game was started

This includes any players that may have disconnected. It returns 0 if the game has not yet started (e.g. the state is not State#INSESSION).

This method is not const because it requires a lock.

Returns
the number of players present when the game was started

◆ getUUID()

std::string cugl::net::NetcodeConnection::getUUID ( )

Returns a globally unique UUID representing this connection.

While room IDs are assigned by the lobby server, connections must assign their own IDs. The only way to guarantee that this IDs are unique is to use Universally Unique Identifiers (UUID) as defined here:

https://en.wikipedia.org/wiki/Universally_unique_identifier

This number is assigned open allocation of this connection. Different connections, even on the same device, have different UUIDs.

This method is not const because it requires a lock.

Returns
a globally unique UUID representing this connection.

◆ isHost()

bool cugl::net::NetcodeConnection::isHost ( ) const
inline

Returns true if this connection is (currently) the game host

Returns
true if this connection is (currently) the game host

◆ isOpen()

bool cugl::net::NetcodeConnection::isOpen ( ) const
inline

Returns true if this connection is open

Technically a connection is not open if the state is CONNECTING.

Returns
true if this connection is open

◆ isPlayerActive()

bool cugl::net::NetcodeConnection::isPlayerActive ( const std::string  player)

Returns true if the given player UUID is currently connected to the game.

This method is not const because it requires a lock.

Parameters
playerThe player to test for connection
Returns
true if the given player UUID is currently connected to the game.

◆ onConnect()

void cugl::net::NetcodeConnection::onConnect ( ConnectionCallback  callback)

Sets a callback function to invoke on player connections

The websocket will keep a player aware of any connections that may happen. This callback will update getPlayers after any such connection. Hence connections can be detected through polling or this callback interface. If this information is important to you, the callback interface is preferred.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe connection callback

◆ onDisconnect()

void cugl::net::NetcodeConnection::onDisconnect ( ConnectionCallback  callback)

Sets a callback function to invoke on player disconnections

The websocket will keep a player aware of any disconnections that may happen. This callback will update getPlayers after any such disconnection. Hence disconnections can be detected through polling or this callback interface. If this information is important to you, the callback interface is preferred.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe disconnection callback

◆ onPromotion()

void cugl::net::NetcodeConnection::onPromotion ( PromotionCallback  callback)

Sets a callback function to invoke on host migration.

Host migration occurs if the host quits (even before the play session starts) without first calling close. During migration, the game lobby will attempt to chose a host. If present, this callback will be invoked (with the argument set to false) for all surviving clients. If no callback function is registered, it is assumed this connection declines to become host. Otherwise, if the callback returns true, this client will be considered as a candidate for the new host.

The game lobby will select a new host if at least one client returns true to the promotion request (otherwise migration fails and all clients are disconnected). If this connection is selected as the new host, the callback will be invoked a second time with the argument set to true. If the callback returns false on that second invocation, it is assumed that the migration failed and all clients are disconnected.

Host migration is only designed for isolated disconnects. If any client disconnects during the host migration process, the migration will fail and all clients will be disconnected.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe promotion callback

◆ onReceipt()

void cugl::net::NetcodeConnection::onReceipt ( Dispatcher  callback)

Sets a callback function to invoke on message receipt

This callback is alternative to the method receive. Instead of buffering messages and calling that method each frame, this callback function will be invoked as soon as the message is received.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe dispatcher callback

◆ onStateChange()

void cugl::net::NetcodeConnection::onStateChange ( StateCallback  callback)

Sets a callback function to invoke on state changes

Monitoring state is one of the most important components of working with a NetcodeConnection. Many state changes (moving from State#CONNECTED to State#INSESSION, or State#INSESSION to State#MIGRATING) can happen due to circumstances beyond the control of this connection. It is particularly important to pay attention to the State#MIGRATING state, as no messages can be sent during that time.

State can either be monitored via a callback with this method, or with a polling the method getState.

Parameters
callbackThe state change callback

◆ open()

void cugl::net::NetcodeConnection::open ( )

Opens the connection to the game lobby sever

This process is not instantaneous. Upon calling this method, you should wait for getState or the callback onStateChange to return State#CONNECTED. Once it does, getRoom will be your assigned room ID.

This method can only be called once. Future calls to this method are ignored. If you need to reopen a closed or failed connection, should should make a new NetcodeConnection object. This method was only separated from the static allocator so that the user could have the opportunity to register callback functions.

◆ receive()

void cugl::net::NetcodeConnection::receive ( const Dispatcher dispatcher)

Receives incoming network messages.

When executed, the function dispatch willl be called on every received byte array since the last call to receive. It is up to you to interpret this data on your own or with NetcodeDeserializer

A network frame can, but need not be, the same as a render frame. Your dispatch function should be prepared to be called multiple times a render frame, or even not at all.

If a dispatcher callback has been registered with onReceipt, this method will never do anything. In that case, messages are not buffered and are processed as soon as they are received.

Parameters
dispatcherThe function to process received data

◆ sendTo()

bool cugl::net::NetcodeConnection::sendTo ( const std::string  dst,
const std::vector< std::byte > &  data 
)

Sends a byte array to the specified connection.

As the underlying connection of this netcode is peer-to-peer, this method can be used to send a communication to any other player in the game, regardless of host status (e.g. two non-host players can communicate this way). If the destination is this connection, the message will be immediately appended to the receipt buffer.

Communication from a source is guaranteed to be ordered. So if connection A sends two messages to connection B, connection B will receive those messages in the same order. However, there is no relationship between the messages coming from different sources.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires a connection be established. Otherwise it will return false. It will also return false if the host is currently migrating.

Parameters
dstThe UUID of the peer to receive the message
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ sendToHost()

bool cugl::net::NetcodeConnection::sendToHost ( const std::vector< std::byte > &  data)

Sends a byte array to the host player.

This method is similar to sendTo, except that it always sends to the host player. If this connection is the host, the message will be immediately appended to the receipt buffer.

Communication from a source is guaranteed to be ordered. So if connection A sends two messages to connection B, connection B will receive those messages in the same order. However, there is no relationship between the messages coming from different sources.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires a connection be established. Otherwise it will return false. It will also return false if the host is currently migrating.

Parameters
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ setCapacity()

void cugl::net::NetcodeConnection::setCapacity ( size_t  capacity)

Sets the message buffer capacity.

It is possible for this connection to recieve several messages over the network before it has a chance to all receive. This buffer stores those messages to be read later. The capacity indicates the number of messages that can be stored.

Note that this is NOT the same as the capacity of a single message. That value was set as part of the initial NetcodeConfig.

Parameters
capacityThe new message buffer capacity.

◆ setDebug()

void cugl::net::NetcodeConnection::setDebug ( bool  flag)

Toggles the debugging status of this connection.

If debugging is active, connections will be quite verbose

Parameters
flagWhether to activate debugging

◆ startSession()

void cugl::net::NetcodeConnection::startSession ( )

Marks the game as started and bans incoming connections.

Note: This can only be called by the host. This method is ignored for clients.

Friends And Related Symbol Documentation

◆ NetcodeManager

friend class NetcodeManager
friend

Allow access to the other netcode classes


The documentation for this class was generated from the following file: