/// <summary> /// Start the Forge Networking server on this Facepunch Steamworks client /// </summary> /// <param name="haveLobby">Boolean used internally to tell whether we have already created the lobby</param> public void Host(bool haveLobby = false) { if (Disposed) { throw new ObjectDisposedException("FacepunchP2PServer", "This object has been disposed and can not be used to connect, please use a new FacepunchP2PServer"); } try { if (!haveLobby) { CreateLobby(); return; } var selfSteamId = SteamClient.SteamId; Client = new CachedFacepunchP2PClient(selfSteamId); Me = new NetworkingPlayer(ServerPlayerCounter++, selfSteamId, true, this) { InstanceGuid = InstanceGuid.ToString() }; // Do any generic initialization in result of the successful bind OnBindSuccessful(); // Create the thread that will be listening for new data from connected clients and start its execution Task.Queue(ReadClients); // Create the thread that will check for player timeouts Task.Queue(() => { commonServerLogic.CheckClientTimeout((player) => { Disconnect(player, true); OnPlayerTimeout(player); CleanupDisconnections(); }); }); // Let myself know I connected successfully OnPlayerConnected(Me); // Set myself as a connected client Me.Connected = true; OnServerCreated(); StartAcceptingConnections(); } 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 SteamClient.SteamId, see inner exception", e); } }
/// <summary> /// Connect this FacepunchP2PClient directly to a steam user's FacepunchP2PServer with SteamId specified /// </summary> /// <param name="hostId">The host's <see cref="SteamId"/> SteamId object</param> /// <param name="pendCreates">Immediately set the NetWorker::PendCreates to true</param> public void Connect(SteamId hostId, bool pendCreates = false) { if (Disposed) { throw new ObjectDisposedException("FacepunchP2PClient", "This object has been disposed and can not be used to connect, please use a new FacepunchP2PClient"); } // 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 CachedFacepunchP2PClient(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, P2PSend.Reliable); Thread.Sleep(3000); } while (!headerExchanged && IsBound && ++connectCounter < CONNECT_TRIES); if (connectCounter >= CONNECT_TRIES) { if (connectAttemptFailed != null) { connectAttemptFailed(this); } } }); } 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 server's SteamId, see inner exception", e); } }