public void SendBatchingResetsPreviousWriter() { // batching adds 8 byte timestamp header const int BatchHeader = 8; // create connection NetworkConnectionToClient connection = new NetworkConnectionToClient(42); // send and update big message byte[] message = { 0x01, 0x02 }; connection.Send(new ArraySegment <byte>(message)); connection.Update(); UpdateTransport(); Assert.That(clientReceived.Count, Is.EqualTo(1)); Assert.That(clientReceived[0].Length, Is.EqualTo(BatchHeader + 2)); Assert.That(clientReceived[0][BatchHeader + 0], Is.EqualTo(0x01)); Assert.That(clientReceived[0][BatchHeader + 1], Is.EqualTo(0x02)); // clear previous clientReceived.Clear(); // send a smaller message message = new byte[] { 0xFF }; connection.Send(new ArraySegment <byte>(message)); connection.Update(); UpdateTransport(); Assert.That(clientReceived.Count, Is.EqualTo(1)); Assert.That(clientReceived[0].Length, Is.EqualTo(BatchHeader + 1)); Assert.That(clientReceived[0][BatchHeader + 0], Is.EqualTo(0xFF)); }
public void SendBatchingResetsPreviousWriter() { // create connection NetworkConnectionToClient connection = new NetworkConnectionToClient(42, true, 0); // send and update big message byte[] message = { 0x01, 0x02 }; connection.Send(new ArraySegment <byte>(message)); connection.Update(); transport.LateUpdate(); Assert.That(clientReceived.Count, Is.EqualTo(1)); Assert.That(clientReceived[0].Length, Is.EqualTo(2)); Assert.That(clientReceived[0][0], Is.EqualTo(0x01)); Assert.That(clientReceived[0][1], Is.EqualTo(0x02)); // clear previous clientReceived.Clear(); // send a smaller message message = new byte[] { 0xFF }; connection.Send(new ArraySegment <byte>(message)); connection.Update(); transport.LateUpdate(); Assert.That(clientReceived.Count, Is.EqualTo(1)); Assert.That(clientReceived[0].Length, Is.EqualTo(1)); Assert.That(clientReceived[0][0], Is.EqualTo(0xFF)); }
/// <summary> /// Called on server when the client's AuthRequestMessage arrives /// </summary> /// <param name="conn">Connection to client.</param> /// <param name="msg">The message payload</param> public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) { Debug.Log($"Authentication Request: {msg.authUsername}"); if (connectionsPendingDisconnect.Contains(conn)) { return; } // check the credentials by calling your web server, database table, playfab api, or any method appropriate. if (!Player.playerNames.Contains(msg.authUsername)) { // Add the name to the HashSet Player.playerNames.Add(msg.authUsername); // Store username in authenticationData // This will be read in Player.OnStartServer // to set the playerName SyncVar. conn.authenticationData = msg.authUsername; // create and send msg to client so it knows to proceed AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 100, message = "Success" }; conn.Send(authResponseMessage); // Accept the successful authentication ServerAccept(conn); } else { connectionsPendingDisconnect.Add(conn); // create and send msg to client so it knows to disconnect AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 200, message = "Username already in use...try again" }; conn.Send(authResponseMessage); // must set NetworkConnection isAuthenticated = false conn.isAuthenticated = false; // disconnect the client after 1 second so that response message gets delivered StartCoroutine(DelayedDisconnect(conn, 1f)); } }
void OnServerCancelMatch(NetworkConnectionToClient conn) { if (!NetworkServer.active || !playerMatches.ContainsKey(conn)) { return; } conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Cancelled }); Guid matchId; if (playerMatches.TryGetValue(conn, out matchId)) { playerMatches.Remove(conn); openMatches.Remove(matchId); foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) { PlayerInfo playerInfo = playerInfos[playerConn]; playerInfo.ready = false; playerInfo.matchId = Guid.Empty; playerInfos[playerConn] = playerInfo; playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); } SendMatchList(); } }
void OnServerJoinMatch(NetworkConnectionToClient conn, Guid matchId) { if (!NetworkServer.active || !matchConnections.ContainsKey(matchId) || !openMatches.ContainsKey(matchId)) { return; } MatchInfo matchInfo = openMatches[matchId]; matchInfo.players++; openMatches[matchId] = matchInfo; matchConnections[matchId].Add(conn); PlayerInfo playerInfo = playerInfos[conn]; playerInfo.ready = false; playerInfo.matchId = matchId; playerInfos[conn] = playerInfo; PlayerInfo[] infos = matchConnections[matchId].Select(playerConn => playerInfos[playerConn]).ToArray(); SendMatchList(); conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Joined, matchId = matchId, playerInfos = infos }); foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) { playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); } }
// This delay is mostly for the host player that loads too fast for the // server to have subscenes async loaded from OnServerSceneChanged ahead of it. IEnumerator AddPlayerDelayed(NetworkConnectionToClient conn) { // Wait for server to async load all subscenes for game instances while (!subscenesLoaded) { yield return(null); } // Send Scene msg to client telling it to load the first additive scene conn.Send(new SceneMessage { sceneName = additiveScenes[0], sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); // We have Network Start Positions in first additive scene...pick one Transform start = GetStartPosition(); // Instantiate player as child of start position - this will place it in the additive scene // This also lets player object "inherit" pos and rot from start position transform GameObject player = Instantiate(playerPrefab, start); // now set parent null to get it out from under the Start Position object player.transform.SetParent(null); // Wait for end of frame before adding the player to ensure Scene Message goes first yield return(new WaitForEndOfFrame()); // Finally spawn the player object for this connection NetworkServer.AddPlayerForConnection(conn, player); }
// This delay is mostly for the host player that loads too fast for the // server to have subscenes async loaded from OnStartServer ahead of it. IEnumerator OnServerAddPlayerDelayed(NetworkConnectionToClient conn) { // wait for server to async load all subscenes for game instances while (!subscenesLoaded) { yield return(null); } // Send Scene message to client to additively load the game scene conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive }); // Wait for end of frame before adding the player to ensure Scene Message goes first yield return(new WaitForEndOfFrame()); base.OnServerAddPlayer(conn); PlayerScore playerScore = conn.identity.GetComponent <PlayerScore>(); playerScore.playerNumber = clientIndex; playerScore.scoreIndex = clientIndex / subScenes.Count; playerScore.matchIndex = clientIndex % subScenes.Count; // Do this only on server, not on clients // This is what allows the NetworkSceneChecker on player and scene objects // to isolate matches per scene instance on server. if (subScenes.Count > 0) { SceneManager.MoveGameObjectToScene(conn.identity.gameObject, subScenes[clientIndex % subScenes.Count]); } clientIndex++; }
void OnServerCreateMatch(NetworkConnectionToClient conn) { if (!NetworkServer.active || playerMatches.ContainsKey(conn)) { return; } Guid newMatchId = Guid.NewGuid(); matchConnections.Add(newMatchId, new HashSet <NetworkConnectionToClient>()); matchConnections[newMatchId].Add(conn); playerMatches.Add(conn, newMatchId); openMatches.Add(newMatchId, new MatchInfo { matchId = newMatchId, maxPlayers = 2, players = 1 }); PlayerInfo playerInfo = playerInfos[conn]; playerInfo.ready = false; playerInfo.matchId = newMatchId; playerInfos[conn] = playerInfo; PlayerInfo[] infos = matchConnections[newMatchId].Select(playerConn => playerInfos[playerConn]).ToArray(); conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Created, matchId = newMatchId, playerInfos = infos }); SendMatchList(); }
/// <summary> /// Called on server when the client's AuthRequestMessage arrives /// </summary> /// <param name="conn">Connection to client.</param> /// <param name="msg">The message payload</param> public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) { //Debug.Log($"Authentication Request: {msg.authUsername} {msg.authPassword}"); if (connectionsPendingDisconnect.Contains(conn)) { return; } // check the credentials by calling your web server, database table, playfab api, or any method appropriate. if (msg.authUsername == serverUsername && msg.authPassword == serverPassword) { // create and send msg to client so it knows to proceed AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 100, message = "Success" }; conn.Send(authResponseMessage); // Accept the successful authentication ServerAccept(conn); } else { connectionsPendingDisconnect.Add(conn); // create and send msg to client so it knows to disconnect AuthResponseMessage authResponseMessage = new AuthResponseMessage { code = 200, message = "Invalid Credentials" }; conn.Send(authResponseMessage); // must set NetworkConnection isAuthenticated = false conn.isAuthenticated = false; // disconnect the client after 1 second so that response message gets delivered StartCoroutine(DelayedDisconnect(conn, 1f)); } }
IEnumerator SendPlayerToNewScene(GameObject player) { if (player.TryGetComponent <NetworkIdentity>(out NetworkIdentity identity)) { NetworkConnectionToClient conn = identity.connectionToClient; if (conn == null) { yield break; } // Tell client to unload previous subscene. No custom handling for this. conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true }); yield return(waitForFade); //Debug.Log($"SendPlayerToNewScene RemovePlayerForConnection {conn} netId:{conn.identity.netId}"); NetworkServer.RemovePlayerForConnection(conn, false); // reposition player on server and client player.transform.position = startPosition; player.transform.LookAt(Vector3.up); // Move player to new subscene. SceneManager.MoveGameObjectToScene(player, SceneManager.GetSceneByPath(destinationScene)); // Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene). conn.Send(new SceneMessage { sceneName = destinationScene, sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); //Debug.Log($"SendPlayerToNewScene AddPlayerForConnection {conn} netId:{conn.identity.netId}"); NetworkServer.AddPlayerForConnection(conn, player); // host client would have been disabled by OnTriggerEnter above if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent <PlayerController>(out PlayerController playerController)) { playerController.enabled = true; } } }
public void Send_WithoutBatching_SendsImmediately() { // create connection and send NetworkConnectionToClient connection = new NetworkConnectionToClient(42, false, 0); byte[] message = { 0x01, 0x02 }; connection.Send(new ArraySegment <byte>(message)); // Send() should send immediately, not only in server.update flushing transport.LateUpdate(); Assert.That(clientReceived.Count, Is.EqualTo(1)); }
void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) { Debug.Log($"connection {conn.connectionId} authenticated with id {msg.clientDeviceID}"); // Store the device id for later reference, e.g. when spawning the player conn.authenticationData = msg.clientDeviceID; // Send a response to client telling it to proceed as authenticated conn.Send(new AuthResponseMessage()); // Accept the successful authentication ServerAccept(conn); }
public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) { Debug.LogFormat("Authentication Request: {0} {1}", msg.AuthUsername, msg.AuthPassword); // check the credentials by calling your web server, database table, playfab api, or any method appropriate. if (msg.AuthUsername == Username && msg.AuthPassword == Password) { // create and send msg to client so it knows to proceed var authResponseMessage = new AuthResponseMessage { Code = 100, Message = "Success" }; conn.Send(authResponseMessage); // Invoke the event to complete a successful authentication base.OnServerAuthenticate(conn); } else { // create and send msg to client so it knows to disconnect var authResponseMessage = new AuthResponseMessage { Code = 200, Message = "Invalid Credentials" }; conn.Send(authResponseMessage); // must set NetworkConnection isAuthenticated = false conn.isAuthenticated = false; // disconnect the client after 1 second so that response message gets delivered StartCoroutine(DelayedDisconnect(conn, 1)); } }
public void Send_BatchesUntilUpdate() { // create connection and send NetworkConnectionToClient connection = new NetworkConnectionToClient(42); byte[] message = { 0x01, 0x02 }; connection.Send(new ArraySegment <byte>(message)); // Send() should only add to batch, not send anything yet UpdateTransport(); Assert.That(clientReceived.Count, Is.EqualTo(0)); // updating the connection should now send connection.Update(); UpdateTransport(); Assert.That(clientReceived.Count, Is.EqualTo(1)); }
void OnServerLeaveMatch(NetworkConnectionToClient conn, Guid matchId) { if (!NetworkServer.active) { return; } MatchInfo matchInfo = openMatches[matchId]; matchInfo.players--; openMatches[matchId] = matchInfo; PlayerInfo playerInfo = playerInfos[conn]; playerInfo.ready = false; playerInfo.matchId = Guid.Empty; playerInfos[conn] = playerInfo; foreach (KeyValuePair <Guid, HashSet <NetworkConnectionToClient> > kvp in matchConnections) { kvp.Value.Remove(conn); } HashSet <NetworkConnectionToClient> connections = matchConnections[matchId]; PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) { playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); } SendMatchList(); conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); }
public void Send_BatchesUntilInterval() { // create connection and send int intervalMilliseconds = 10; float intervalSeconds = intervalMilliseconds / 1000f; NetworkConnectionToClient connection = new NetworkConnectionToClient(42, true, intervalSeconds); byte[] message = { 0x01, 0x02 }; connection.Send(new ArraySegment <byte>(message)); // Send() and update shouldn't send yet until interval elapsed connection.Update(); transport.LateUpdate(); Assert.That(clientReceived.Count, Is.EqualTo(0)); // wait 'interval' Thread.Sleep(intervalMilliseconds); // updating again should flush out the batch connection.Update(); transport.LateUpdate(); Assert.That(clientReceived.Count, Is.EqualTo(1)); }
/// <summary> /// Sends updated match list to all waiting connections or just one if specified /// </summary> /// <param name="conn"></param> internal void SendMatchList(NetworkConnectionToClient conn = null) { if (!NetworkServer.active) { return; } if (conn != null) { conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); } else { foreach (NetworkConnectionToClient waiter in waitingConnections) { waiter.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); } } }