/// <summary>
/// This will connect a UDP client to a given UDP server
/// </summary>
/// <param name="host">The server's host address on the network</param>
/// <param name="port">The port that the server is hosting on</param>
/// <param name="natHost">The NAT server host address, if blank NAT will be skipped</param>
/// <param name="natPort">The port that the NAT server is hosting on</param>
/// <param name="pendCreates">Immidiately set the NetWorker::PendCreates to true</param>
public void Connect(CSteamID hostId, bool pendCreates = false)
{
if (Disposed)
{
throw new ObjectDisposedException("UDPClient", "This object has been disposed and can not be used to connect, please use a new UDPClient");
}
if (hostId.IsLobby())
{
//If this is a lobby we need to join it, make direct connection to the owner.
m_JoinCall = SteamMatchmaking.JoinLobby(hostId);
m_LobbyEntered = Callback <LobbyEnter_t> .Create((LobbyEnter_t data) =>
{
LobbyID = (CSteamID)data.m_ulSteamIDLobby;
//Get the owner and attempt a direct connection
Connect(SteamMatchmaking.GetLobbyOwner(LobbyID), pendCreates);
});
return;
}
// By default pending creates should be true and flushed when ready
if (!pendCreates)
{
PendCreates = true;
}
try
{
ushort clientPort = DEFAULT_PORT;
// Make sure not to listen on the same port as the server for local networks
if (clientPort == DEFAULT_PORT)
{
clientPort++;
}
Client = new CachedSteamP2PClient(hostId);
// Do any generic initialization in result of the successful bind
OnBindSuccessful();
// Get a random hash key that needs to be used for validating that the server was connected to
headerHash = Websockets.HeaderHashKey();
// This is a typical Websockets accept header to be validated
byte[] connectHeader = Websockets.ConnectionHeader(headerHash, DEFAULT_PORT);
// Setup the identity of the server as a player
server = new NetworkingPlayer(0, hostId, true, this);
// Create the thread that will be listening for new data from connected clients and start its execution
Task.Queue(ReadNetwork);
//Let myself know I connected successfully
OnPlayerConnected(server);
// Set myself as a connected client
server.Connected = true;
//Set the port
SetPort(clientPort);
int connectCounter = 0;
Task.Queue(() =>
{
do
{
// Send the accept headers to the server to validate
Client.Send(connectHeader, connectHeader.Length, hostId, EP2PSend.k_EP2PSendReliable);
Thread.Sleep(3000);
} while (!headerExchanged && IsBound && ++connectCounter < CONNECT_TRIES);
if (connectCounter >= CONNECT_TRIES)
{
if (connectAttemptFailed != null)
{
connectAttemptFailed(this);
}
}
});
m_CallbackP2PSessionConnectFail = Callback <P2PSessionConnectFail_t> .Create((P2PSessionConnectFail_t data) =>
{
if (data.m_eP2PSessionError > 0)
{
Disconnect(true);
switch (data.m_eP2PSessionError)
{
case 1:
Logging.BMSLog.LogException("The target user is not running the same game."); break;
case 2:
Logging.BMSLog.LogException("The local user doesn't own the app that is running."); break;
case 3:
Logging.BMSLog.LogException("Target user isn't connected to Steam."); break;
case 4:
Logging.BMSLog.LogException("The connection timed out because the target user didn't respond, perhaps they aren't calling AcceptP2PSessionWithUser"); break;
}
}
//
});
}
catch (Exception e)
{
Logging.BMSLog.LogException(e);
// Do any generic initialization in result of the binding failure
OnBindFailure();
throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
}
}