mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
Lobby to Room (#1065)
* Change Lobby to Room with Obsoletes * Changed folder from Lobby to Room * Updated docs * reverted leftover debu.log line * Fixed OfflineGUI * Changed the obsolete classes to inherit from the new ones. * Fixed SyncVar hook
This commit is contained in:
parent
b3030aff85
commit
0e95016e95
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
@ -15,645 +16,7 @@ namespace Mirror
|
||||
/// <para>The OnLobby*() functions have empty implementations on the NetworkLobbyManager base class, so the base class functions do not have to be called.</para>
|
||||
/// </remarks>
|
||||
[AddComponentMenu("Network/NetworkLobbyManager")]
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkLobbyManager.html")]
|
||||
public class NetworkLobbyManager : NetworkManager
|
||||
{
|
||||
public struct PendingPlayer
|
||||
{
|
||||
public NetworkConnection conn;
|
||||
public GameObject lobbyPlayer;
|
||||
}
|
||||
|
||||
[Header("Lobby Settings")]
|
||||
|
||||
[FormerlySerializedAs("m_ShowLobbyGUI")]
|
||||
[SerializeField]
|
||||
internal bool showLobbyGUI = true;
|
||||
|
||||
[FormerlySerializedAs("m_MinPlayers")]
|
||||
[SerializeField]
|
||||
int minPlayers = 1;
|
||||
|
||||
[FormerlySerializedAs("m_LobbyPlayerPrefab")]
|
||||
[SerializeField]
|
||||
NetworkLobbyPlayer lobbyPlayerPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to use for the lobby. This is similar to the offlineScene of the NetworkManager.
|
||||
/// </summary>
|
||||
[Scene]
|
||||
public string LobbyScene;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to use for the playing the game from the lobby. This is similar to the onlineScene of the NetworkManager.
|
||||
/// </summary>
|
||||
[Scene]
|
||||
public string GameplayScene;
|
||||
|
||||
/// <summary>
|
||||
/// List of players that are in the Lobby
|
||||
/// </summary>
|
||||
[FormerlySerializedAs("m_PendingPlayers")]
|
||||
public List<PendingPlayer> pendingPlayers = new List<PendingPlayer>();
|
||||
|
||||
/// <summary>
|
||||
/// These slots track players that enter the lobby.
|
||||
/// <para>The slotId on players is global to the game - across all players.</para>
|
||||
/// </summary>
|
||||
public List<NetworkLobbyPlayer> lobbySlots = new List<NetworkLobbyPlayer>();
|
||||
|
||||
/// <summary>
|
||||
/// True when all players have submitted a Ready message
|
||||
/// </summary>
|
||||
public bool allPlayersReady;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
// always >= 0
|
||||
maxConnections = Mathf.Max(maxConnections, 0);
|
||||
|
||||
// always <= maxConnections
|
||||
minPlayers = Mathf.Min(minPlayers, maxConnections);
|
||||
|
||||
// always >= 0
|
||||
minPlayers = Mathf.Max(minPlayers, 0);
|
||||
|
||||
if (lobbyPlayerPrefab != null)
|
||||
{
|
||||
NetworkIdentity identity = lobbyPlayerPrefab.GetComponent<NetworkIdentity>();
|
||||
if (identity == null)
|
||||
{
|
||||
lobbyPlayerPrefab = null;
|
||||
Debug.LogError("LobbyPlayer prefab must have a NetworkIdentity component.");
|
||||
}
|
||||
}
|
||||
|
||||
base.OnValidate();
|
||||
}
|
||||
|
||||
internal void ReadyStatusChanged()
|
||||
{
|
||||
int CurrentPlayers = 0;
|
||||
int ReadyPlayers = 0;
|
||||
|
||||
foreach (NetworkLobbyPlayer item in lobbySlots)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
CurrentPlayers++;
|
||||
if (item.readyToBegin)
|
||||
ReadyPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentPlayers == ReadyPlayers)
|
||||
CheckReadyToBegin();
|
||||
else
|
||||
allPlayersReady = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerReady(NetworkConnection conn)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.Log("NetworkLobbyManager OnServerReady");
|
||||
base.OnServerReady(conn);
|
||||
|
||||
if (conn != null && conn.playerController != null)
|
||||
{
|
||||
GameObject lobbyPlayer = conn.playerController.gameObject;
|
||||
|
||||
// if null or not a lobby player, dont replace it
|
||||
if (lobbyPlayer != null && lobbyPlayer.GetComponent<NetworkLobbyPlayer>() != null)
|
||||
SceneLoadedForPlayer(conn, lobbyPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneLoadedForPlayer(NetworkConnection conn, GameObject lobbyPlayer)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("NetworkLobby SceneLoadedForPlayer scene: {0} {1}", SceneManager.GetActiveScene().name, conn);
|
||||
|
||||
if (SceneManager.GetActiveScene().name == LobbyScene)
|
||||
{
|
||||
// cant be ready in lobby, add to ready list
|
||||
PendingPlayer pending;
|
||||
pending.conn = conn;
|
||||
pending.lobbyPlayer = lobbyPlayer;
|
||||
pendingPlayers.Add(pending);
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject gamePlayer = OnLobbyServerCreateGamePlayer(conn);
|
||||
if (gamePlayer == null)
|
||||
{
|
||||
// get start position from base class
|
||||
Transform startPos = GetStartPosition();
|
||||
gamePlayer = startPos != null
|
||||
? Instantiate(playerPrefab, startPos.position, startPos.rotation)
|
||||
: Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
|
||||
gamePlayer.name = playerPrefab.name;
|
||||
}
|
||||
|
||||
if (!OnLobbyServerSceneLoadedForPlayer(lobbyPlayer, gamePlayer))
|
||||
return;
|
||||
|
||||
// replace lobby player with game player
|
||||
NetworkServer.ReplacePlayerForConnection(conn, gamePlayer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CheckReadyToBegin checks all of the players in the lobby to see if their readyToBegin flag is set.
|
||||
/// <para>If all of the players are ready, then the server switches from the LobbyScene to the PlayScene - essentially starting the game. This is called automatically in response to NetworkLobbyPlayer.SendReadyToBeginMessage().</para>
|
||||
/// </summary>
|
||||
public void CheckReadyToBegin()
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name != LobbyScene) return;
|
||||
|
||||
if (minPlayers > 0 && NetworkServer.connections.Count(conn => conn.Value != null && conn.Value.playerController.gameObject.GetComponent<NetworkLobbyPlayer>().readyToBegin) < minPlayers)
|
||||
{
|
||||
allPlayersReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
pendingPlayers.Clear();
|
||||
allPlayersReady = true;
|
||||
OnLobbyServerPlayersReady();
|
||||
}
|
||||
|
||||
void CallOnClientEnterLobby()
|
||||
{
|
||||
OnLobbyClientEnter();
|
||||
foreach (NetworkLobbyPlayer player in lobbySlots)
|
||||
if (player != null)
|
||||
{
|
||||
player.OnClientEnterLobby();
|
||||
}
|
||||
}
|
||||
|
||||
void CallOnClientExitLobby()
|
||||
{
|
||||
OnLobbyClientExit();
|
||||
foreach (NetworkLobbyPlayer player in lobbySlots)
|
||||
if (player != null)
|
||||
{
|
||||
player.OnClientExitLobby();
|
||||
}
|
||||
}
|
||||
|
||||
#region server handlers
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerConnect(NetworkConnection conn)
|
||||
{
|
||||
if (numPlayers >= maxConnections)
|
||||
{
|
||||
conn.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
// cannot join game in progress
|
||||
if (SceneManager.GetActiveScene().name != LobbyScene)
|
||||
{
|
||||
conn.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnServerConnect(conn);
|
||||
OnLobbyServerConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerDisconnect(NetworkConnection conn)
|
||||
{
|
||||
if (conn.playerController != null)
|
||||
{
|
||||
NetworkLobbyPlayer player = conn.playerController.GetComponent<NetworkLobbyPlayer>();
|
||||
|
||||
if (player != null)
|
||||
lobbySlots.Remove(player);
|
||||
}
|
||||
|
||||
allPlayersReady = false;
|
||||
|
||||
foreach (NetworkLobbyPlayer player in lobbySlots)
|
||||
{
|
||||
if (player != null)
|
||||
player.GetComponent<NetworkLobbyPlayer>().readyToBegin = false;
|
||||
}
|
||||
|
||||
if (SceneManager.GetActiveScene().name == LobbyScene)
|
||||
RecalculateLobbyPlayerIndices();
|
||||
|
||||
base.OnServerDisconnect(conn);
|
||||
OnLobbyServerDisconnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
/// <param name="extraMessage"></param>
|
||||
public override void OnServerAddPlayer(NetworkConnection conn, AddPlayerMessage extraMessage)
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name != LobbyScene) return;
|
||||
|
||||
if (lobbySlots.Count == maxConnections) return;
|
||||
|
||||
allPlayersReady = false;
|
||||
|
||||
if (LogFilter.Debug) Debug.LogFormat("NetworkLobbyManager.OnServerAddPlayer playerPrefab:{0}", lobbyPlayerPrefab.name);
|
||||
|
||||
GameObject newLobbyGameObject = OnLobbyServerCreateLobbyPlayer(conn);
|
||||
if (newLobbyGameObject == null)
|
||||
newLobbyGameObject = (GameObject)Instantiate(lobbyPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity);
|
||||
|
||||
NetworkLobbyPlayer newLobbyPlayer = newLobbyGameObject.GetComponent<NetworkLobbyPlayer>();
|
||||
|
||||
lobbySlots.Add(newLobbyPlayer);
|
||||
|
||||
RecalculateLobbyPlayerIndices();
|
||||
|
||||
NetworkServer.AddPlayerForConnection(conn, newLobbyGameObject);
|
||||
}
|
||||
|
||||
void RecalculateLobbyPlayerIndices()
|
||||
{
|
||||
if (lobbySlots.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < lobbySlots.Count; i++)
|
||||
{
|
||||
lobbySlots[i].index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
public override void ServerChangeScene(string sceneName)
|
||||
{
|
||||
if (sceneName == LobbyScene)
|
||||
{
|
||||
foreach (NetworkLobbyPlayer lobbyPlayer in lobbySlots)
|
||||
{
|
||||
if (lobbyPlayer == null) continue;
|
||||
|
||||
// find the game-player object for this connection, and destroy it
|
||||
NetworkIdentity identity = lobbyPlayer.GetComponent<NetworkIdentity>();
|
||||
|
||||
NetworkIdentity playerController = identity.connectionToClient.playerController;
|
||||
NetworkServer.Destroy(playerController.gameObject);
|
||||
|
||||
if (NetworkServer.active)
|
||||
{
|
||||
// re-add the lobby object
|
||||
lobbyPlayer.GetComponent<NetworkLobbyPlayer>().readyToBegin = false;
|
||||
NetworkServer.ReplacePlayerForConnection(identity.connectionToClient, lobbyPlayer.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dontDestroyOnLoad)
|
||||
{
|
||||
foreach (NetworkLobbyPlayer lobbyPlayer in lobbySlots)
|
||||
{
|
||||
if (lobbyPlayer != null)
|
||||
{
|
||||
lobbyPlayer.transform.SetParent(null);
|
||||
DontDestroyOnLoad(lobbyPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.ServerChangeScene(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
public override void OnServerSceneChanged(string sceneName)
|
||||
{
|
||||
if (sceneName != LobbyScene)
|
||||
{
|
||||
// call SceneLoadedForPlayer on any players that become ready while we were loading the scene.
|
||||
foreach (PendingPlayer pending in pendingPlayers)
|
||||
SceneLoadedForPlayer(pending.conn, pending.lobbyPlayer);
|
||||
|
||||
pendingPlayers.Clear();
|
||||
}
|
||||
|
||||
OnLobbyServerSceneChanged(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartServer()
|
||||
{
|
||||
if (string.IsNullOrEmpty(LobbyScene))
|
||||
{
|
||||
Debug.LogError("NetworkLobbyManager LobbyScene is empty. Set the LobbyScene in the inspector for the NetworkLobbyMangaer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(GameplayScene))
|
||||
{
|
||||
Debug.LogError("NetworkLobbyManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkLobbyMangaer");
|
||||
return;
|
||||
}
|
||||
|
||||
OnLobbyStartServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartHost()
|
||||
{
|
||||
OnLobbyStartHost();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopServer()
|
||||
{
|
||||
lobbySlots.Clear();
|
||||
base.OnStopServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopHost()
|
||||
{
|
||||
OnLobbyStopHost();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region client handlers
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartClient()
|
||||
{
|
||||
if (lobbyPlayerPrefab == null || lobbyPlayerPrefab.gameObject == null)
|
||||
Debug.LogError("NetworkLobbyManager no LobbyPlayer prefab is registered. Please add a LobbyPlayer prefab.");
|
||||
else
|
||||
ClientScene.RegisterPrefab(lobbyPlayerPrefab.gameObject);
|
||||
|
||||
if (playerPrefab == null)
|
||||
Debug.LogError("NetworkLobbyManager no GamePlayer prefab is registered. Please add a GamePlayer prefab.");
|
||||
else
|
||||
ClientScene.RegisterPrefab(playerPrefab);
|
||||
|
||||
OnLobbyStartClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientConnect(NetworkConnection conn)
|
||||
{
|
||||
OnLobbyClientConnect(conn);
|
||||
CallOnClientEnterLobby();
|
||||
base.OnClientConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientDisconnect(NetworkConnection conn)
|
||||
{
|
||||
OnLobbyClientDisconnect(conn);
|
||||
base.OnClientDisconnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopClient()
|
||||
{
|
||||
OnLobbyStopClient();
|
||||
CallOnClientExitLobby();
|
||||
|
||||
if (!string.IsNullOrEmpty(offlineScene))
|
||||
{
|
||||
// Move the LobbyManager from the virtual DontDestroyOnLoad scene to the Game scene.
|
||||
// This let's it be destroyed when client changes to the Offline scene.
|
||||
SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="newSceneName"></param>
|
||||
public override void OnClientChangeScene(string newSceneName)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientChangeScene from {0} to {1}", SceneManager.GetActiveScene().name, newSceneName);
|
||||
|
||||
if (SceneManager.GetActiveScene().name == LobbyScene && newSceneName == GameplayScene && dontDestroyOnLoad && NetworkClient.isConnected)
|
||||
{
|
||||
if (NetworkClient.connection != null && NetworkClient.connection.playerController != null)
|
||||
{
|
||||
GameObject lobbyPlayer = NetworkClient.connection.playerController.gameObject;
|
||||
if (lobbyPlayer != null)
|
||||
{
|
||||
lobbyPlayer.transform.SetParent(null);
|
||||
DontDestroyOnLoad(lobbyPlayer);
|
||||
}
|
||||
else
|
||||
Debug.LogWarningFormat("OnClientChangeScene: lobbyPlayer is null");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientChangeScene {0} {1}", dontDestroyOnLoad, NetworkClient.isConnected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientSceneChanged(NetworkConnection conn)
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name == LobbyScene)
|
||||
{
|
||||
if (NetworkClient.isConnected)
|
||||
CallOnClientEnterLobby();
|
||||
}
|
||||
else
|
||||
CallOnClientExitLobby();
|
||||
|
||||
base.OnClientSceneChanged(conn);
|
||||
OnLobbyClientSceneChanged(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region lobby server virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the host when a host is started.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyStartHost() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the host when the host is stopped.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyStopHost() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when the server is started - including when a host is started.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyStartServer() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a new client connects to the server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The new connection.</param>
|
||||
public virtual void OnLobbyServerConnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a client disconnects.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that disconnected.</param>
|
||||
public virtual void OnLobbyServerDisconnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a networked scene finishes loading.
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the new scene.</param>
|
||||
public virtual void OnLobbyServerSceneChanged(string sceneName) { }
|
||||
|
||||
/// <summary>
|
||||
/// This allows customization of the creation of the lobby-player object on the server.
|
||||
/// <para>By default the lobbyPlayerPrefab is used to create the lobby-player, but this function allows that behaviour to be customized.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection the player object is for.</param>
|
||||
/// <returns>The new lobby-player object.</returns>
|
||||
public virtual GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This allows customization of the creation of the GamePlayer object on the server.
|
||||
/// <para>By default the gamePlayerPrefab is used to create the game-player, but this function allows that behaviour to be customized. The object returned from the function will be used to replace the lobby-player on the connection.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection the player object is for.</param>
|
||||
/// <returns>A new GamePlayer object.</returns>
|
||||
public virtual GameObject OnLobbyServerCreateGamePlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// for users to apply settings from their lobby player object to their in-game player object
|
||||
/// <summary>
|
||||
/// This is called on the server when it is told that a client has finished switching from the lobby scene to a game player scene.
|
||||
/// <para>When switching from the lobby, the lobby-player is replaced with a game-player object. This callback function gives an opportunity to apply state from the lobby-player to the game-player object.</para>
|
||||
/// </summary>
|
||||
/// <param name="lobbyPlayer">The lobby player object.</param>
|
||||
/// <param name="gamePlayer">The game player object.</param>
|
||||
/// <returns>False to not allow this player to replace the lobby player.</returns>
|
||||
public virtual bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when all the players in the lobby are ready.
|
||||
/// <para>The default implementation of this function uses ServerChangeScene() to switch to the game player scene. By implementing this callback you can customize what happens when all the players in the lobby are ready, such as adding a countdown or a confirmation for a group leader.</para>
|
||||
/// </summary>
|
||||
public virtual void OnLobbyServerPlayersReady()
|
||||
{
|
||||
// all players are readyToBegin, start the game
|
||||
ServerChangeScene(GameplayScene);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region lobby client virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook to allow custom behaviour when the game client enters the lobby.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyClientEnter() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook to allow custom behaviour when the game client exits the lobby.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyClientExit() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when it connects to server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that connected.</param>
|
||||
public virtual void OnLobbyClientConnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when disconnected from a server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that disconnected.</param>
|
||||
public virtual void OnLobbyClientDisconnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when a client is started.
|
||||
/// </summary>
|
||||
/// <param name="lobbyClient">The connection for the lobby.</param>
|
||||
public virtual void OnLobbyStartClient() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when the client stops.
|
||||
/// </summary>
|
||||
public virtual void OnLobbyStopClient() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when the client is finished loading a new networked scene.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that finished loading a new networked scene.</param>
|
||||
public virtual void OnLobbyClientSceneChanged(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// Called on the client when adding a player to the lobby fails.
|
||||
/// <para>This could be because the lobby is full, or the connection is not allowed to have more players.</para>
|
||||
/// </summary>
|
||||
public virtual void OnLobbyClientAddPlayerFailed() { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region optional UI
|
||||
|
||||
/// <summary>
|
||||
/// virtual so inheriting classes can roll their own
|
||||
/// </summary>
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!showLobbyGUI)
|
||||
return;
|
||||
|
||||
if (SceneManager.GetActiveScene().name != LobbyScene)
|
||||
return;
|
||||
|
||||
GUI.Box(new Rect(10f, 180f, 520f, 150f), "PLAYERS");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkRoomManager.html")]
|
||||
[Obsolete("Use / inherit from NetworkRoomManager instead")]
|
||||
public class NetworkLobbyManager : NetworkRoomManager { }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 615e6c6589cf9e54cad646b5a11e0529
|
||||
guid: a4c96e6dd99826849ab1431f94547141
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
@ -9,147 +10,7 @@ namespace Mirror
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Network/NetworkLobbyPlayer")]
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkLobbyPlayer.html")]
|
||||
public class NetworkLobbyPlayer : NetworkBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// This flag controls whether the default UI is shown for the lobby player.
|
||||
/// <para>As this UI is rendered using the old GUI system, it is only recommended for testing purposes.</para>
|
||||
/// </summary>
|
||||
public bool showLobbyGUI = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is a flag that control whether this player is ready for the game to begin.
|
||||
/// <para>When all players are ready to begin, the game will start. This should not be set directly, the SendReadyToBeginMessage function should be called on the client to set it on the server.</para>
|
||||
/// </summary>
|
||||
[SyncVar(hook = nameof(ReadyStateChanged))]
|
||||
public bool readyToBegin;
|
||||
|
||||
/// <summary>
|
||||
/// Current index of the player, e.g. Player1, Player2, etc.
|
||||
/// </summary>
|
||||
[SyncVar]
|
||||
public int index;
|
||||
|
||||
#region Unity Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Do not use Start - Override OnStartrHost / OnStartClient instead!
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
if (NetworkManager.singleton as NetworkLobbyManager)
|
||||
OnClientEnterLobby();
|
||||
else
|
||||
Debug.LogError("LobbyPlayer could not find a NetworkLobbyManager. The LobbyPlayer requires a NetworkLobbyManager object to function. Make sure that there is one in the scene.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
[Command]
|
||||
public void CmdChangeReadyState(bool readyState)
|
||||
{
|
||||
readyToBegin = readyState;
|
||||
NetworkLobbyManager lobby = NetworkManager.singleton as NetworkLobbyManager;
|
||||
if (lobby != null)
|
||||
{
|
||||
lobby.ReadyStatusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SyncVar Hooks
|
||||
|
||||
void ReadyStateChanged(bool newReadyState)
|
||||
{
|
||||
OnClientReady(readyToBegin);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lobby Client Virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on all player objects when entering the lobby.
|
||||
/// <para>Note: isLocalPlayer is not guaranteed to be set until OnStartLocalPlayer is called.</para>
|
||||
/// </summary>
|
||||
public virtual void OnClientEnterLobby() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on all player objects when exiting the lobby.
|
||||
/// </summary>
|
||||
public virtual void OnClientExitLobby() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on clients when a LobbyPlayer switches between ready or not ready.
|
||||
/// <para>This function is called when the a client player calls SendReadyToBeginMessage() or SendNotReadyToBeginMessage().</para>
|
||||
/// </summary>
|
||||
/// <param name="readyState">Whether the player is ready or not.</param>
|
||||
public virtual void OnClientReady(bool readyState) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Optional UI
|
||||
|
||||
/// <summary>
|
||||
/// Render a UI for the lobby. Override to provide your on UI
|
||||
/// </summary>
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!showLobbyGUI)
|
||||
return;
|
||||
|
||||
NetworkLobbyManager lobby = NetworkManager.singleton as NetworkLobbyManager;
|
||||
if (lobby)
|
||||
{
|
||||
if (!lobby.showLobbyGUI)
|
||||
return;
|
||||
|
||||
if (SceneManager.GetActiveScene().name != lobby.LobbyScene)
|
||||
return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(20f + (index * 100), 200f, 90f, 130f));
|
||||
|
||||
GUILayout.Label($"Player [{index + 1}]");
|
||||
|
||||
if (readyToBegin)
|
||||
GUILayout.Label("Ready");
|
||||
else
|
||||
GUILayout.Label("Not Ready");
|
||||
|
||||
if (((isServer && index > 0) || isServerOnly) && GUILayout.Button("REMOVE"))
|
||||
{
|
||||
// This button only shows on the Host for all players other than the Host
|
||||
// Host and Players can't remove themselves (stop the client instead)
|
||||
// Host can kick a Player this way.
|
||||
GetComponent<NetworkIdentity>().connectionToClient.Disconnect();
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
if (NetworkClient.active && isLocalPlayer)
|
||||
{
|
||||
GUILayout.BeginArea(new Rect(20f, 300f, 120f, 20f));
|
||||
|
||||
if (readyToBegin)
|
||||
{
|
||||
if (GUILayout.Button("Cancel"))
|
||||
CmdChangeReadyState(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Ready"))
|
||||
CmdChangeReadyState(true);
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkRoomPlayer.html")]
|
||||
[Obsolete("Use / inherit from NetworkRoomPlayer instead")]
|
||||
public class NetworkLobbyPlayer : NetworkRoomPlayer { }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79874ac94d5b1314788ecf0e86bd23fd
|
||||
guid: 777a368af85f2e84da7ea5666581921b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
659
Assets/Mirror/Components/NetworkRoomManager.cs
Normal file
659
Assets/Mirror/Components/NetworkRoomManager.cs
Normal file
@ -0,0 +1,659 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a specialized NetworkManager that includes a networked room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The room has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkRoomPlayer component be on the room player objects.</para>
|
||||
/// <para>NetworkRoomManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkRoomManager, there are new virtual functions on the NetworkRoomManager that begin with "OnRoom". These should be used on classes derived from NetworkRoomManager instead of the virtual functions on NetworkManager.</para>
|
||||
/// <para>The OnRoom*() functions have empty implementations on the NetworkRoomManager base class, so the base class functions do not have to be called.</para>
|
||||
/// </remarks>
|
||||
[AddComponentMenu("Network/NetworkRoomManager")]
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkRoomManager.html")]
|
||||
public class NetworkRoomManager : NetworkManager
|
||||
{
|
||||
public struct PendingPlayer
|
||||
{
|
||||
public NetworkConnection conn;
|
||||
public GameObject roomPlayer;
|
||||
}
|
||||
|
||||
[Header("Room Settings")]
|
||||
|
||||
[FormerlySerializedAs("m_ShowRoomGUI")]
|
||||
[SerializeField]
|
||||
internal bool showRoomGUI = true;
|
||||
|
||||
[FormerlySerializedAs("m_MinPlayers")]
|
||||
[SerializeField]
|
||||
int minPlayers = 1;
|
||||
|
||||
[FormerlySerializedAs("m_RoomPlayerPrefab")]
|
||||
[SerializeField]
|
||||
NetworkRoomPlayer roomPlayerPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to use for the room. This is similar to the offlineScene of the NetworkManager.
|
||||
/// </summary>
|
||||
[Scene]
|
||||
public string RoomScene;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to use for the playing the game from the room. This is similar to the onlineScene of the NetworkManager.
|
||||
/// </summary>
|
||||
[Scene]
|
||||
public string GameplayScene;
|
||||
|
||||
/// <summary>
|
||||
/// List of players that are in the Room
|
||||
/// </summary>
|
||||
[FormerlySerializedAs("m_PendingPlayers")]
|
||||
public List<PendingPlayer> pendingPlayers = new List<PendingPlayer>();
|
||||
|
||||
/// <summary>
|
||||
/// These slots track players that enter the room.
|
||||
/// <para>The slotId on players is global to the game - across all players.</para>
|
||||
/// </summary>
|
||||
public List<NetworkRoomPlayer> roomSlots = new List<NetworkRoomPlayer>();
|
||||
|
||||
/// <summary>
|
||||
/// True when all players have submitted a Ready message
|
||||
/// </summary>
|
||||
public bool allPlayersReady;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
// always >= 0
|
||||
maxConnections = Mathf.Max(maxConnections, 0);
|
||||
|
||||
// always <= maxConnections
|
||||
minPlayers = Mathf.Min(minPlayers, maxConnections);
|
||||
|
||||
// always >= 0
|
||||
minPlayers = Mathf.Max(minPlayers, 0);
|
||||
|
||||
if (roomPlayerPrefab != null)
|
||||
{
|
||||
NetworkIdentity identity = roomPlayerPrefab.GetComponent<NetworkIdentity>();
|
||||
if (identity == null)
|
||||
{
|
||||
roomPlayerPrefab = null;
|
||||
Debug.LogError("RoomPlayer prefab must have a NetworkIdentity component.");
|
||||
}
|
||||
}
|
||||
|
||||
base.OnValidate();
|
||||
}
|
||||
|
||||
internal void ReadyStatusChanged()
|
||||
{
|
||||
int CurrentPlayers = 0;
|
||||
int ReadyPlayers = 0;
|
||||
|
||||
foreach (NetworkRoomPlayer item in roomSlots)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
CurrentPlayers++;
|
||||
if (item.readyToBegin)
|
||||
ReadyPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentPlayers == ReadyPlayers)
|
||||
CheckReadyToBegin();
|
||||
else
|
||||
allPlayersReady = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerReady(NetworkConnection conn)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.Log("NetworkRoomManager OnServerReady");
|
||||
base.OnServerReady(conn);
|
||||
|
||||
if (conn != null && conn.playerController != null)
|
||||
{
|
||||
GameObject roomPlayer = conn.playerController.gameObject;
|
||||
|
||||
// if null or not a room player, dont replace it
|
||||
if (roomPlayer != null && roomPlayer.GetComponent<NetworkRoomPlayer>() != null)
|
||||
SceneLoadedForPlayer(conn, roomPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneLoadedForPlayer(NetworkConnection conn, GameObject roomPlayer)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("NetworkRoom SceneLoadedForPlayer scene: {0} {1}", SceneManager.GetActiveScene().name, conn);
|
||||
|
||||
if (SceneManager.GetActiveScene().name == RoomScene)
|
||||
{
|
||||
// cant be ready in room, add to ready list
|
||||
PendingPlayer pending;
|
||||
pending.conn = conn;
|
||||
pending.roomPlayer = roomPlayer;
|
||||
pendingPlayers.Add(pending);
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject gamePlayer = OnRoomServerCreateGamePlayer(conn);
|
||||
if (gamePlayer == null)
|
||||
{
|
||||
// get start position from base class
|
||||
Transform startPos = GetStartPosition();
|
||||
gamePlayer = startPos != null
|
||||
? Instantiate(playerPrefab, startPos.position, startPos.rotation)
|
||||
: Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
|
||||
gamePlayer.name = playerPrefab.name;
|
||||
}
|
||||
|
||||
if (!OnRoomServerSceneLoadedForPlayer(roomPlayer, gamePlayer))
|
||||
return;
|
||||
|
||||
// replace room player with game player
|
||||
NetworkServer.ReplacePlayerForConnection(conn, gamePlayer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CheckReadyToBegin checks all of the players in the room to see if their readyToBegin flag is set.
|
||||
/// <para>If all of the players are ready, then the server switches from the RoomScene to the PlayScene - essentially starting the game. This is called automatically in response to NetworkRoomPlayer.SendReadyToBeginMessage().</para>
|
||||
/// </summary>
|
||||
public void CheckReadyToBegin()
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name != RoomScene) return;
|
||||
|
||||
if (minPlayers > 0 && NetworkServer.connections.Count(conn => conn.Value != null && conn.Value.playerController.gameObject.GetComponent<NetworkRoomPlayer>().readyToBegin) < minPlayers)
|
||||
{
|
||||
allPlayersReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
pendingPlayers.Clear();
|
||||
allPlayersReady = true;
|
||||
OnRoomServerPlayersReady();
|
||||
}
|
||||
|
||||
void CallOnClientEnterRoom()
|
||||
{
|
||||
OnRoomClientEnter();
|
||||
foreach (NetworkRoomPlayer player in roomSlots)
|
||||
if (player != null)
|
||||
{
|
||||
player.OnClientEnterRoom();
|
||||
}
|
||||
}
|
||||
|
||||
void CallOnClientExitRoom()
|
||||
{
|
||||
OnRoomClientExit();
|
||||
foreach (NetworkRoomPlayer player in roomSlots)
|
||||
if (player != null)
|
||||
{
|
||||
player.OnClientExitRoom();
|
||||
}
|
||||
}
|
||||
|
||||
#region server handlers
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerConnect(NetworkConnection conn)
|
||||
{
|
||||
if (numPlayers >= maxConnections)
|
||||
{
|
||||
conn.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
// cannot join game in progress
|
||||
if (SceneManager.GetActiveScene().name != RoomScene)
|
||||
{
|
||||
conn.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnServerConnect(conn);
|
||||
OnRoomServerConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnServerDisconnect(NetworkConnection conn)
|
||||
{
|
||||
if (conn.playerController != null)
|
||||
{
|
||||
NetworkRoomPlayer player = conn.playerController.GetComponent<NetworkRoomPlayer>();
|
||||
|
||||
if (player != null)
|
||||
roomSlots.Remove(player);
|
||||
}
|
||||
|
||||
allPlayersReady = false;
|
||||
|
||||
foreach (NetworkRoomPlayer player in roomSlots)
|
||||
{
|
||||
if (player != null)
|
||||
player.GetComponent<NetworkRoomPlayer>().readyToBegin = false;
|
||||
}
|
||||
|
||||
if (SceneManager.GetActiveScene().name == RoomScene)
|
||||
RecalculateRoomPlayerIndices();
|
||||
|
||||
base.OnServerDisconnect(conn);
|
||||
OnRoomServerDisconnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
/// <param name="extraMessage"></param>
|
||||
public override void OnServerAddPlayer(NetworkConnection conn, AddPlayerMessage extraMessage)
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name != RoomScene) return;
|
||||
|
||||
if (roomSlots.Count == maxConnections) return;
|
||||
|
||||
allPlayersReady = false;
|
||||
|
||||
if (LogFilter.Debug) Debug.LogFormat("NetworkRoomManager.OnServerAddPlayer playerPrefab:{0}", roomPlayerPrefab.name);
|
||||
|
||||
GameObject newRoomGameObject = OnRoomServerCreateRoomPlayer(conn);
|
||||
if (newRoomGameObject == null)
|
||||
newRoomGameObject = (GameObject)Instantiate(roomPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity);
|
||||
|
||||
NetworkRoomPlayer newRoomPlayer = newRoomGameObject.GetComponent<NetworkRoomPlayer>();
|
||||
|
||||
roomSlots.Add(newRoomPlayer);
|
||||
|
||||
RecalculateRoomPlayerIndices();
|
||||
|
||||
NetworkServer.AddPlayerForConnection(conn, newRoomGameObject);
|
||||
}
|
||||
|
||||
void RecalculateRoomPlayerIndices()
|
||||
{
|
||||
if (roomSlots.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < roomSlots.Count; i++)
|
||||
{
|
||||
roomSlots[i].index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
public override void ServerChangeScene(string sceneName)
|
||||
{
|
||||
if (sceneName == RoomScene)
|
||||
{
|
||||
foreach (NetworkRoomPlayer roomPlayer in roomSlots)
|
||||
{
|
||||
if (roomPlayer == null) continue;
|
||||
|
||||
// find the game-player object for this connection, and destroy it
|
||||
NetworkIdentity identity = roomPlayer.GetComponent<NetworkIdentity>();
|
||||
|
||||
NetworkIdentity playerController = identity.connectionToClient.playerController;
|
||||
NetworkServer.Destroy(playerController.gameObject);
|
||||
|
||||
if (NetworkServer.active)
|
||||
{
|
||||
// re-add the room object
|
||||
roomPlayer.GetComponent<NetworkRoomPlayer>().readyToBegin = false;
|
||||
NetworkServer.ReplacePlayerForConnection(identity.connectionToClient, roomPlayer.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dontDestroyOnLoad)
|
||||
{
|
||||
foreach (NetworkRoomPlayer roomPlayer in roomSlots)
|
||||
{
|
||||
if (roomPlayer != null)
|
||||
{
|
||||
roomPlayer.transform.SetParent(null);
|
||||
DontDestroyOnLoad(roomPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.ServerChangeScene(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
public override void OnServerSceneChanged(string sceneName)
|
||||
{
|
||||
if (sceneName != RoomScene)
|
||||
{
|
||||
// call SceneLoadedForPlayer on any players that become ready while we were loading the scene.
|
||||
foreach (PendingPlayer pending in pendingPlayers)
|
||||
SceneLoadedForPlayer(pending.conn, pending.roomPlayer);
|
||||
|
||||
pendingPlayers.Clear();
|
||||
}
|
||||
|
||||
OnRoomServerSceneChanged(sceneName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartServer()
|
||||
{
|
||||
if (string.IsNullOrEmpty(RoomScene))
|
||||
{
|
||||
Debug.LogError("NetworkRoomManager RoomScene is empty. Set the RoomScene in the inspector for the NetworkRoomMangaer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(GameplayScene))
|
||||
{
|
||||
Debug.LogError("NetworkRoomManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkRoomMangaer");
|
||||
return;
|
||||
}
|
||||
|
||||
OnRoomStartServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartHost()
|
||||
{
|
||||
OnRoomStartHost();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopServer()
|
||||
{
|
||||
roomSlots.Clear();
|
||||
base.OnStopServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopHost()
|
||||
{
|
||||
OnRoomStopHost();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region client handlers
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStartClient()
|
||||
{
|
||||
if (roomPlayerPrefab == null || roomPlayerPrefab.gameObject == null)
|
||||
Debug.LogError("NetworkRoomManager no RoomPlayer prefab is registered. Please add a RoomPlayer prefab.");
|
||||
else
|
||||
ClientScene.RegisterPrefab(roomPlayerPrefab.gameObject);
|
||||
|
||||
if (playerPrefab == null)
|
||||
Debug.LogError("NetworkRoomManager no GamePlayer prefab is registered. Please add a GamePlayer prefab.");
|
||||
else
|
||||
ClientScene.RegisterPrefab(playerPrefab);
|
||||
|
||||
OnRoomStartClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientConnect(NetworkConnection conn)
|
||||
{
|
||||
OnRoomClientConnect(conn);
|
||||
CallOnClientEnterRoom();
|
||||
base.OnClientConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientDisconnect(NetworkConnection conn)
|
||||
{
|
||||
OnRoomClientDisconnect(conn);
|
||||
base.OnClientDisconnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void OnStopClient()
|
||||
{
|
||||
OnRoomStopClient();
|
||||
CallOnClientExitRoom();
|
||||
|
||||
if (!string.IsNullOrEmpty(offlineScene))
|
||||
{
|
||||
// Move the RoomManager from the virtual DontDestroyOnLoad scene to the Game scene.
|
||||
// This let's it be destroyed when client changes to the Offline scene.
|
||||
SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="newSceneName"></param>
|
||||
public override void OnClientChangeScene(string newSceneName)
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientChangeScene from {0} to {1}", SceneManager.GetActiveScene().name, newSceneName);
|
||||
|
||||
if (SceneManager.GetActiveScene().name == RoomScene && newSceneName == GameplayScene && dontDestroyOnLoad && NetworkClient.isConnected)
|
||||
{
|
||||
if (NetworkClient.connection != null && NetworkClient.connection.playerController != null)
|
||||
{
|
||||
GameObject roomPlayer = NetworkClient.connection.playerController.gameObject;
|
||||
if (roomPlayer != null)
|
||||
{
|
||||
roomPlayer.transform.SetParent(null);
|
||||
DontDestroyOnLoad(roomPlayer);
|
||||
}
|
||||
else
|
||||
Debug.LogWarningFormat("OnClientChangeScene: roomPlayer is null");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientChangeScene {0} {1}", dontDestroyOnLoad, NetworkClient.isConnected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection of the client</param>
|
||||
public override void OnClientSceneChanged(NetworkConnection conn)
|
||||
{
|
||||
if (SceneManager.GetActiveScene().name == RoomScene)
|
||||
{
|
||||
if (NetworkClient.isConnected)
|
||||
CallOnClientEnterRoom();
|
||||
}
|
||||
else
|
||||
CallOnClientExitRoom();
|
||||
|
||||
base.OnClientSceneChanged(conn);
|
||||
OnRoomClientSceneChanged(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region room server virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the host when a host is started.
|
||||
/// </summary>
|
||||
public virtual void OnRoomStartHost() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the host when the host is stopped.
|
||||
/// </summary>
|
||||
public virtual void OnRoomStopHost() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when the server is started - including when a host is started.
|
||||
/// </summary>
|
||||
public virtual void OnRoomStartServer() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a new client connects to the server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The new connection.</param>
|
||||
public virtual void OnRoomServerConnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a client disconnects.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that disconnected.</param>
|
||||
public virtual void OnRoomServerDisconnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when a networked scene finishes loading.
|
||||
/// </summary>
|
||||
/// <param name="sceneName">Name of the new scene.</param>
|
||||
public virtual void OnRoomServerSceneChanged(string sceneName) { }
|
||||
|
||||
/// <summary>
|
||||
/// This allows customization of the creation of the room-player object on the server.
|
||||
/// <para>By default the roomPlayerPrefab is used to create the room-player, but this function allows that behaviour to be customized.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection the player object is for.</param>
|
||||
/// <returns>The new room-player object.</returns>
|
||||
public virtual GameObject OnRoomServerCreateRoomPlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This allows customization of the creation of the GamePlayer object on the server.
|
||||
/// <para>By default the gamePlayerPrefab is used to create the game-player, but this function allows that behaviour to be customized. The object returned from the function will be used to replace the room-player on the connection.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection the player object is for.</param>
|
||||
/// <returns>A new GamePlayer object.</returns>
|
||||
public virtual GameObject OnRoomServerCreateGamePlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// for users to apply settings from their room player object to their in-game player object
|
||||
/// <summary>
|
||||
/// This is called on the server when it is told that a client has finished switching from the room scene to a game player scene.
|
||||
/// <para>When switching from the room, the room-player is replaced with a game-player object. This callback function gives an opportunity to apply state from the room-player to the game-player object.</para>
|
||||
/// </summary>
|
||||
/// <param name="roomPlayer">The room player object.</param>
|
||||
/// <param name="gamePlayer">The game player object.</param>
|
||||
/// <returns>False to not allow this player to replace the room player.</returns>
|
||||
public virtual bool OnRoomServerSceneLoadedForPlayer(GameObject roomPlayer, GameObject gamePlayer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the server when all the players in the room are ready.
|
||||
/// <para>The default implementation of this function uses ServerChangeScene() to switch to the game player scene. By implementing this callback you can customize what happens when all the players in the room are ready, such as adding a countdown or a confirmation for a group leader.</para>
|
||||
/// </summary>
|
||||
public virtual void OnRoomServerPlayersReady()
|
||||
{
|
||||
// all players are readyToBegin, start the game
|
||||
ServerChangeScene(GameplayScene);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region room client virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook to allow custom behaviour when the game client enters the room.
|
||||
/// </summary>
|
||||
public virtual void OnRoomClientEnter() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook to allow custom behaviour when the game client exits the room.
|
||||
/// </summary>
|
||||
public virtual void OnRoomClientExit() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when it connects to server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that connected.</param>
|
||||
public virtual void OnRoomClientConnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when disconnected from a server.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that disconnected.</param>
|
||||
public virtual void OnRoomClientDisconnect(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when a client is started.
|
||||
/// </summary>
|
||||
/// <param name="roomClient">The connection for the room.</param>
|
||||
public virtual void OnRoomStartClient() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when the client stops.
|
||||
/// </summary>
|
||||
public virtual void OnRoomStopClient() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is called on the client when the client is finished loading a new networked scene.
|
||||
/// </summary>
|
||||
/// <param name="conn">The connection that finished loading a new networked scene.</param>
|
||||
public virtual void OnRoomClientSceneChanged(NetworkConnection conn) { }
|
||||
|
||||
/// <summary>
|
||||
/// Called on the client when adding a player to the room fails.
|
||||
/// <para>This could be because the room is full, or the connection is not allowed to have more players.</para>
|
||||
/// </summary>
|
||||
public virtual void OnRoomClientAddPlayerFailed() { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region optional UI
|
||||
|
||||
/// <summary>
|
||||
/// virtual so inheriting classes can roll their own
|
||||
/// </summary>
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!showRoomGUI)
|
||||
return;
|
||||
|
||||
if (SceneManager.GetActiveScene().name != RoomScene)
|
||||
return;
|
||||
|
||||
GUI.Box(new Rect(10f, 180f, 520f, 150f), "PLAYERS");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
11
Assets/Mirror/Components/NetworkRoomManager.cs.meta
Normal file
11
Assets/Mirror/Components/NetworkRoomManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 615e6c6589cf9e54cad646b5a11e0529
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
155
Assets/Mirror/Components/NetworkRoomPlayer.cs
Normal file
155
Assets/Mirror/Components/NetworkRoomPlayer.cs
Normal file
@ -0,0 +1,155 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
/// <summary>
|
||||
/// This component works in conjunction with the NetworkRoomManager to make up the multiplayer room system.
|
||||
/// <para>The RoomPrefab object of the NetworkRoomManager must have this component on it. This component holds basic room player data required for the room to function. Game specific data for room players can be put in other components on the RoomPrefab or in scripts derived from NetworkRoomPlayer.</para>
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Network/NetworkRoomPlayer")]
|
||||
[HelpURL("https://mirror-networking.com/xmldocs/articles/Components/NetworkRoomPlayer.html")]
|
||||
public class NetworkRoomPlayer : NetworkBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// This flag controls whether the default UI is shown for the room player.
|
||||
/// <para>As this UI is rendered using the old GUI system, it is only recommended for testing purposes.</para>
|
||||
/// </summary>
|
||||
public bool showRoomGUI = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is a flag that control whether this player is ready for the game to begin.
|
||||
/// <para>When all players are ready to begin, the game will start. This should not be set directly, the SendReadyToBeginMessage function should be called on the client to set it on the server.</para>
|
||||
/// </summary>
|
||||
[SyncVar(hook = nameof(ReadyStateChanged))]
|
||||
public bool readyToBegin;
|
||||
|
||||
/// <summary>
|
||||
/// Current index of the player, e.g. Player1, Player2, etc.
|
||||
/// </summary>
|
||||
[SyncVar]
|
||||
public int index;
|
||||
|
||||
#region Unity Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Do not use Start - Override OnStartrHost / OnStartClient instead!
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
if (NetworkManager.singleton as NetworkRoomManager)
|
||||
OnClientEnterRoom();
|
||||
else
|
||||
Debug.LogError("RoomPlayer could not find a NetworkRoomManager. The RoomPlayer requires a NetworkRoomManager object to function. Make sure that there is one in the scene.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
[Command]
|
||||
public void CmdChangeReadyState(bool readyState)
|
||||
{
|
||||
readyToBegin = readyState;
|
||||
NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager;
|
||||
if (room != null)
|
||||
{
|
||||
room.ReadyStatusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SyncVar Hooks
|
||||
|
||||
void ReadyStateChanged(bool newReadyState)
|
||||
{
|
||||
OnClientReady(newReadyState);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Room Client Virtuals
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on all player objects when entering the room.
|
||||
/// <para>Note: isLocalPlayer is not guaranteed to be set until OnStartLocalPlayer is called.</para>
|
||||
/// </summary>
|
||||
public virtual void OnClientEnterRoom() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on all player objects when exiting the room.
|
||||
/// </summary>
|
||||
public virtual void OnClientExitRoom() { }
|
||||
|
||||
/// <summary>
|
||||
/// This is a hook that is invoked on clients when a RoomPlayer switches between ready or not ready.
|
||||
/// <para>This function is called when the a client player calls SendReadyToBeginMessage() or SendNotReadyToBeginMessage().</para>
|
||||
/// </summary>
|
||||
/// <param name="readyState">Whether the player is ready or not.</param>
|
||||
public virtual void OnClientReady(bool readyState) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Optional UI
|
||||
|
||||
/// <summary>
|
||||
/// Render a UI for the room. Override to provide your on UI
|
||||
/// </summary>
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!showRoomGUI)
|
||||
return;
|
||||
|
||||
NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager;
|
||||
if (room)
|
||||
{
|
||||
if (!room.showRoomGUI)
|
||||
return;
|
||||
|
||||
if (SceneManager.GetActiveScene().name != room.RoomScene)
|
||||
return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(20f + (index * 100), 200f, 90f, 130f));
|
||||
|
||||
GUILayout.Label($"Player [{index + 1}]");
|
||||
|
||||
if (readyToBegin)
|
||||
GUILayout.Label("Ready");
|
||||
else
|
||||
GUILayout.Label("Not Ready");
|
||||
|
||||
if (((isServer && index > 0) || isServerOnly) && GUILayout.Button("REMOVE"))
|
||||
{
|
||||
// This button only shows on the Host for all players other than the Host
|
||||
// Host and Players can't remove themselves (stop the client instead)
|
||||
// Host can kick a Player this way.
|
||||
GetComponent<NetworkIdentity>().connectionToClient.Disconnect();
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
if (NetworkClient.active && isLocalPlayer)
|
||||
{
|
||||
GUILayout.BeginArea(new Rect(20f, 300f, 120f, 20f));
|
||||
|
||||
if (readyToBegin)
|
||||
{
|
||||
if (GUILayout.Button("Cancel"))
|
||||
CmdChangeReadyState(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Ready"))
|
||||
CmdChangeReadyState(true);
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
11
Assets/Mirror/Components/NetworkRoomPlayer.cs.meta
Normal file
11
Assets/Mirror/Components/NetworkRoomPlayer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79874ac94d5b1314788ecf0e86bd23fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,39 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
{
|
||||
public class NetworkLobbyPlayerExt : NetworkLobbyPlayer
|
||||
{
|
||||
public override void OnStartClient()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnStartClient {0}", SceneManager.GetActiveScene().name);
|
||||
|
||||
base.OnStartClient();
|
||||
NetworkLobbyManager lobby = NetworkManager.singleton as NetworkLobbyManager;
|
||||
|
||||
/*
|
||||
This demonstrates how to set the parent of the LobbyPlayerPrefab to an arbitrary scene object
|
||||
A similar technique would be used if a full canvas layout UI existed and we wanted to show
|
||||
something more visual for each player in that layout, such as a name, avatar, etc.
|
||||
|
||||
Note: LobbyPlayer prefab will be marked DontDestroyOnLoad and carried forward to the game scene.
|
||||
Because of this, NetworkLobbyManager must automatically set the parent to null
|
||||
in ServerChangeScene and OnClientChangeScene.
|
||||
*/
|
||||
|
||||
if (lobby != null && SceneManager.GetActiveScene().name == lobby.LobbyScene)
|
||||
gameObject.transform.SetParent(GameObject.Find("Players").transform);
|
||||
}
|
||||
|
||||
public override void OnClientEnterLobby()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientEnterLobby {0}", SceneManager.GetActiveScene().name);
|
||||
}
|
||||
|
||||
public override void OnClientExitLobby()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientExitLobby {0}", SceneManager.GetActiveScene().name);
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
@ -1,14 +1,14 @@
|
||||
# Lobby Example
|
||||
# Room Example
|
||||
|
||||
In Build Settings, remove all scenes and add all of the scenes from the Examples\Lobby\Scenes folder in the following order:
|
||||
In Build Settings, remove all scenes and add all of the scenes from the Examples\Room\Scenes folder in the following order:
|
||||
|
||||
- Offline
|
||||
- Lobby
|
||||
- Room
|
||||
- Online
|
||||
|
||||
If you opened the Lobby scene before doing the above steps, you may have to reassign the scenes to the NetworkLobbyManagerExt component of the LobbyManager scene object.
|
||||
If you opened the Room scene before doing the above steps, you may have to reassign the scenes to the NetworkRoomManagerExt component of the RoomManager scene object.
|
||||
|
||||
** Do not assign anything to the Online scene field!** If you do, the lobby will be bypassed. Assign **only* the Offline and Lobby and Gameplay scene fields in the inspector.
|
||||
** Do not assign anything to the Online scene field!** If you do, the room will be bypassed. Assign **only* the Offline and Room and Gameplay scene fields in the inspector.
|
||||
|
||||
File -> Build and Run
|
||||
|
@ -207,4 +207,4 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 039bde4e5e3b63e46be9b967d06e5469, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
LobbyScene: LobbyScene
|
||||
RoomScene: RoomScene
|
@ -237,7 +237,7 @@ GameObject:
|
||||
- component: {fileID: 2008127831}
|
||||
- component: {fileID: 2008127830}
|
||||
m_Layer: 0
|
||||
m_Name: LobbyManager
|
||||
m_Name: RoomManager
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -263,7 +263,7 @@ MonoBehaviour:
|
||||
OnClientDataReceived:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: Mirror.UnityEventByteArray, Mirror, Version=0.0.0.0, Culture=neutral,
|
||||
m_TypeName: Mirror.UnityEventArraySegment, Mirror, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
OnClientError:
|
||||
m_PersistentCalls:
|
||||
@ -282,7 +282,7 @@ MonoBehaviour:
|
||||
OnServerDataReceived:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: Mirror.UnityEventIntByteArray, Mirror, Version=0.0.0.0, Culture=neutral,
|
||||
m_TypeName: Mirror.UnityEventIntArraySegment, Mirror, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
OnServerError:
|
||||
m_PersistentCalls:
|
||||
@ -295,7 +295,8 @@ MonoBehaviour:
|
||||
m_TypeName: Mirror.UnityEventInt, Mirror, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
port: 7780
|
||||
NoDelay: 1
|
||||
MaxMessageSize: 16384
|
||||
serverMaxMessageSize: 16384
|
||||
clientMaxMessageSize: 16384
|
||||
--- !u!114 &2008127831
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -324,13 +325,13 @@ MonoBehaviour:
|
||||
playerSpawnMethod: 1
|
||||
spawnPrefabs:
|
||||
- {fileID: 1139254171913846, guid: 52f1c9ea06cfd154cb68ff9d1b66fc13, type: 3}
|
||||
showLobbyGUI: 1
|
||||
showRoomGUI: 1
|
||||
minPlayers: 1
|
||||
lobbyPlayerPrefab: {fileID: 114033720796874720, guid: deae2134a1d77704b9c595efe69767dd,
|
||||
roomPlayerPrefab: {fileID: 114033720796874720, guid: deae2134a1d77704b9c595efe69767dd,
|
||||
type: 3}
|
||||
LobbyScene: LobbyScene
|
||||
RoomScene: RoomScene
|
||||
GameplayScene: OnlineScene
|
||||
lobbySlots: []
|
||||
roomSlots: []
|
||||
allPlayersReady: 0
|
||||
--- !u!4 &2008127832
|
||||
Transform:
|
@ -1,42 +1,43 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
public class NetworkLobbyManagerExt : NetworkLobbyManager
|
||||
[AddComponentMenu("")]
|
||||
public class NetworkRoomManagerExt : NetworkRoomManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Called just after GamePlayer object is instantiated and just before it replaces LobbyPlayer object.
|
||||
/// Called just after GamePlayer object is instantiated and just before it replaces RoomPlayer object.
|
||||
/// This is the ideal point to pass any data like player name, credentials, tokens, colors, etc.
|
||||
/// into the GamePlayer object as it is about to enter the Online scene.
|
||||
/// </summary>
|
||||
/// <param name="lobbyPlayer"></param>
|
||||
/// <param name="roomPlayer"></param>
|
||||
/// <param name="gamePlayer"></param>
|
||||
/// <returns>true unless some code in here decides it needs to abort the replacement</returns>
|
||||
public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
|
||||
public override bool OnRoomServerSceneLoadedForPlayer(GameObject roomPlayer, GameObject gamePlayer)
|
||||
{
|
||||
PlayerController player = gamePlayer.GetComponent<PlayerController>();
|
||||
player.index = lobbyPlayer.GetComponent<NetworkLobbyPlayer>().index;
|
||||
player.index = roomPlayer.GetComponent<NetworkRoomPlayer>().index;
|
||||
player.playerColor = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
This code below is to demonstrate how to do a Start button that only appears for the Host player
|
||||
showStartButton is a local bool that's needed because OnLobbyServerPlayersReady is only fired when
|
||||
showStartButton is a local bool that's needed because OnRoomServerPlayersReady is only fired when
|
||||
all players are ready, but if a player cancels their ready state there's no callback to set it back to false
|
||||
Therefore, allPlayersReady is used in combination with showStartButton to show/hide the Start button correctly.
|
||||
Setting showStartButton false when the button is pressed hides it in the game scene since NetworkLobbyManager
|
||||
Setting showStartButton false when the button is pressed hides it in the game scene since NetworkRoomManager
|
||||
is set as DontDestroyOnLoad = true.
|
||||
*/
|
||||
|
||||
bool showStartButton;
|
||||
|
||||
public override void OnLobbyServerPlayersReady()
|
||||
public override void OnRoomServerPlayersReady()
|
||||
{
|
||||
// calling the base method calls ServerChangeScene as soon as all players are in Ready state.
|
||||
if (isHeadless)
|
||||
base.OnLobbyServerPlayersReady();
|
||||
base.OnRoomServerPlayersReady();
|
||||
else
|
||||
showStartButton = true;
|
||||
}
|
40
Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs
Normal file
40
Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class NetworkRoomPlayerExt : NetworkRoomPlayer
|
||||
{
|
||||
public override void OnStartClient()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnStartClient {0}", SceneManager.GetActiveScene().name);
|
||||
|
||||
base.OnStartClient();
|
||||
NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager;
|
||||
|
||||
/*
|
||||
This demonstrates how to set the parent of the RoomPlayerPrefab to an arbitrary scene object
|
||||
A similar technique would be used if a full canvas layout UI existed and we wanted to show
|
||||
something more visual for each player in that layout, such as a name, avatar, etc.
|
||||
|
||||
Note: RoomPlayer prefab will be marked DontDestroyOnLoad and carried forward to the game scene.
|
||||
Because of this, NetworkRoomManager must automatically set the parent to null
|
||||
in ServerChangeScene and OnClientChangeScene.
|
||||
*/
|
||||
|
||||
if (room != null && SceneManager.GetActiveScene().name == room.RoomScene)
|
||||
gameObject.transform.SetParent(GameObject.Find("Players").transform);
|
||||
}
|
||||
|
||||
public override void OnClientEnterRoom()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientEnterRoom {0}", SceneManager.GetActiveScene().name);
|
||||
}
|
||||
|
||||
public override void OnClientExitRoom()
|
||||
{
|
||||
if (LogFilter.Debug) Debug.LogFormat("OnClientExitRoom {0}", SceneManager.GetActiveScene().name);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
public class OfflineGUI : MonoBehaviour
|
||||
{
|
||||
[Scene]
|
||||
public string LobbyScene;
|
||||
public string RoomScene;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@ -22,7 +22,7 @@ void OnGUI()
|
||||
GUILayout.Box("WASDQE keys to move & turn\nTouch the spheres for points\nLighter colors score higher");
|
||||
|
||||
if (GUILayout.Button("Join Game"))
|
||||
SceneManager.LoadScene(LobbyScene);
|
||||
SceneManager.LoadScene(RoomScene);
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public class PlayerController : NetworkBehaviour
|
@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
public class Reward : NetworkBehaviour
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Examples.NetworkLobby
|
||||
namespace Mirror.Examples.NetworkRoom
|
||||
{
|
||||
public class Spawner : NetworkBehaviour
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
# NetworkLobbyManager
|
||||
# NetworkRoomManager
|
||||
|
||||
\*\*Please see the Lobby example in the Examples folder in your Mirror folder
|
||||
\*\*Please see the Room example in the Examples folder in your Mirror folder
|
||||
|
||||
The Network Lobby Manager is a specialized type of [Network Manager](NetworkManager.md) that provides a multiplayer lobby before entering the main play scene of the game. It allows you to set up a network with:
|
||||
The Network Room Manager is a specialized type of [Network Manager](NetworkManager.md) that provides a multiplayer room before entering the main play scene of the game. It allows you to set up a network with:
|
||||
|
||||
- A maximum player limit
|
||||
|
||||
@ -10,11 +10,11 @@ The Network Lobby Manager is a specialized type of [Network Manager](NetworkMana
|
||||
|
||||
- Option to prevent players from joining a game in progress
|
||||
|
||||
- Customizable ways for players to choose options while in lobby
|
||||
- Customizable ways for players to choose options while in room
|
||||
|
||||
There are two types of player objects with the Network Lobby Manager:
|
||||
There are two types of player objects with the Network Room Manager:
|
||||
|
||||
**Lobby Player Prefab**
|
||||
**Room Player Prefab**
|
||||
|
||||
- One for each player
|
||||
|
||||
@ -24,9 +24,9 @@ There are two types of player objects with the Network Lobby Manager:
|
||||
|
||||
- Holds ready flag and configuration data
|
||||
|
||||
- Handles commands in the lobby
|
||||
- Handles commands in the room
|
||||
|
||||
- Must use the [Network Lobby Player](NetworkLobbyPlayer.md) component
|
||||
- Must use the [Network Room Player](NetworkRoomPlayer.md) component
|
||||
|
||||
**Player Prefab**
|
||||
|
||||
@ -38,21 +38,21 @@ There are two types of player objects with the Network Lobby Manager:
|
||||
|
||||
- Handles commands in the game
|
||||
|
||||
![Network Lobby Manager](NetworkLobbyManager.PNG)
|
||||
![Network Room Manager](NetworkRoomManager.PNG)
|
||||
|
||||
## Properties
|
||||
|
||||
- **Show Lobby GUI**
|
||||
Show the default OnGUI controls for the lobby.
|
||||
- **Show Room GUI**
|
||||
Show the default OnGUI controls for the room.
|
||||
|
||||
- **Min Players**
|
||||
Minimum number of players needed to start a game.
|
||||
|
||||
- **Lobby Player Prefab**
|
||||
The prefab to create for players when they enter the lobby (requires Network Lobby Player component).
|
||||
- **Room Player Prefab**
|
||||
The prefab to create for players when they enter the room (requires Network Room Player component).
|
||||
|
||||
- **Lobby Scene**
|
||||
The scene to use for the lobby.
|
||||
- **Room Scene**
|
||||
The scene to use for the room.
|
||||
|
||||
- **Gameplay Scene**
|
||||
The scene to use for main game play.
|
||||
@ -60,8 +60,8 @@ There are two types of player objects with the Network Lobby Manager:
|
||||
- **pendingPlayers**
|
||||
List\<PendingPlayer\> that holds players that are ready to start playing.
|
||||
|
||||
- **lobbySlots**
|
||||
List\<NetworkLobbyPlayer\> that manages the slots for connected clients in the lobby.
|
||||
- **roomSlots**
|
||||
List\<NetworkRoomPlayer\> that manages the slots for connected clients in the room.
|
||||
|
||||
- **allPlayersReady**
|
||||
Bool indicating if all players are ready to start playing. This value changes as players invoke `CmdChangeReadyState` indicating true or false, and will be set false when a new client connects.
|
||||
@ -71,34 +71,34 @@ There are two types of player objects with the Network Lobby Manager:
|
||||
### Server Virtual Methods
|
||||
|
||||
```cs
|
||||
public virtual void OnLobbyStartHost() {}
|
||||
public virtual void OnRoomStartHost() {}
|
||||
|
||||
public virtual void OnLobbyStopHost() {}
|
||||
public virtual void OnRoomStopHost() {}
|
||||
|
||||
public virtual void OnLobbyStartServer() {}
|
||||
public virtual void OnRoomStartServer() {}
|
||||
|
||||
public virtual void OnLobbyServerConnect(NetworkConnection conn) {}
|
||||
public virtual void OnRoomServerConnect(NetworkConnection conn) {}
|
||||
|
||||
public virtual void OnLobbyServerDisconnect(NetworkConnection conn) {}
|
||||
public virtual void OnRoomServerDisconnect(NetworkConnection conn) {}
|
||||
|
||||
public virtual void OnLobbyServerSceneChanged(string sceneName) {}
|
||||
public virtual void OnRoomServerSceneChanged(string sceneName) {}
|
||||
|
||||
public virtual GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn)
|
||||
public virtual GameObject OnRoomServerCreateRoomPlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual GameObject OnLobbyServerCreateGamePlayer(NetworkConnection conn)
|
||||
public virtual GameObject OnRoomServerCreateGamePlayer(NetworkConnection conn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
|
||||
public virtual bool OnRoomServerSceneLoadedForPlayer(GameObject roomPlayer, GameObject gamePlayer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void OnLobbyServerPlayersReady()
|
||||
public virtual void OnRoomServerPlayersReady()
|
||||
{
|
||||
ServerChangeScene(GameplayScene);
|
||||
}
|
||||
@ -107,19 +107,19 @@ public virtual void OnLobbyServerPlayersReady()
|
||||
### Client Virtual Methods
|
||||
|
||||
```cs
|
||||
public virtual void OnLobbyClientEnter() {}
|
||||
public virtual void OnRoomClientEnter() {}
|
||||
|
||||
public virtual void OnLobbyClientExit() {}
|
||||
public virtual void OnRoomClientExit() {}
|
||||
|
||||
public virtual void OnLobbyClientConnect(NetworkConnection conn) {}
|
||||
public virtual void OnRoomClientConnect(NetworkConnection conn) {}
|
||||
|
||||
public virtual void OnLobbyClientDisconnect(NetworkConnection conn) {}
|
||||
public virtual void OnRoomClientDisconnect(NetworkConnection conn) {}
|
||||
|
||||
public virtual void OnLobbyStartClient() {}
|
||||
public virtual void OnRoomStartClient() {}
|
||||
|
||||
public virtual void OnLobbyStopClient() {}
|
||||
public virtual void OnRoomStopClient() {}
|
||||
|
||||
public virtual void OnLobbyClientSceneChanged(NetworkConnection conn) {}
|
||||
public virtual void OnRoomClientSceneChanged(NetworkConnection conn) {}
|
||||
|
||||
public virtual void OnLobbyClientAddPlayerFailed() {}
|
||||
public virtual void OnRoomClientAddPlayerFailed() {}
|
||||
```
|
||||
|
@ -1,31 +1,31 @@
|
||||
# NetworkLobbyPlayer
|
||||
# NetworkRoomPlayer
|
||||
|
||||
The Network Lobby Player stores per-player state for the [Network Lobby Manager](NetworkLobbyManager.md) while in the lobby. When using this component, you need to write a script which allows players to indicate they are ready to begin playing, which sets the ReadyToBegin property.
|
||||
The Network Room Player stores per-player state for the [Network Room Manager](NetworkRoomManager.md) while in the room. When using this component, you need to write a script which allows players to indicate they are ready to begin playing, which sets the ReadyToBegin property.
|
||||
|
||||
A game object with a Network Lobby Player component must also have a Network Identity component. When you create a Network Lobby Player component on a game object, Unity also creates a Network Identity component on that game object if it does not already have one.
|
||||
A game object with a Network Room Player component must also have a Network Identity component. When you create a Network Room Player component on a game object, Unity also creates a Network Identity component on that game object if it does not already have one.
|
||||
|
||||
![Network Lobby Player](NetworkLobbyPlayer.PNG)
|
||||
![Network Room Player](NetworkRoomPlayer.PNG)
|
||||
|
||||
- **Show Lobby GUI**
|
||||
Enable this to show the developer GUI for players in the lobby. This UI is only intended to be used for ease of development. This is enabled by default.
|
||||
- **Show Room GUI**
|
||||
Enable this to show the developer GUI for players in the room. This UI is only intended to be used for ease of development. This is enabled by default.
|
||||
|
||||
- **Ready To Begin**
|
||||
Enable this to have lobby players automatically be set to Ready.
|
||||
Enable this to have room players automatically be set to Ready.
|
||||
|
||||
- **Index**
|
||||
Sequential index of the player, e.g. Player 1, Player 2, etc.
|
||||
|
||||
- **Network Sync Interval**
|
||||
The rate at which information is sent from the Network Lobby Player to the server.
|
||||
The rate at which information is sent from the Network Room Player to the server.
|
||||
|
||||
## Methods
|
||||
|
||||
### Client Virtual Methods
|
||||
|
||||
```cs
|
||||
public virtual void OnClientEnterLobby() {}
|
||||
public virtual void OnClientEnterRoom() {}
|
||||
|
||||
public virtual void OnClientExitLobby() {}
|
||||
public virtual void OnClientExitRoom() {}
|
||||
|
||||
public virtual void OnClientReady(bool readyState) {}
|
||||
```
|
||||
|
@ -4,10 +4,10 @@ General description of Components
|
||||
|
||||
- [NetworkManager](NetworkManager.md)
|
||||
The Network Manager is a component for managing the networking aspects of a multiplayer game.
|
||||
- [NetworkLobbyManager](NetworkLobbyManager.md)
|
||||
The Network Lobby Manager is an extension component of Network Manager that provides a basic functional lobby.
|
||||
- [NetworkLobbyPlayer](NetworkLobbyPlayer.md)
|
||||
The Network Lobby Player is a component that's required on Player prefabs used in the Lobby Scene with the Network Lobby Manager above.
|
||||
- [NetworkRoomManager](NetworkRoomManager.md)
|
||||
The Network Room Manager is an extension component of Network Manager that provides a basic functional room.
|
||||
- [NetworkRoomPlayer](NetworkRoomPlayer.md)
|
||||
The Network Room Player is a component that's required on Player prefabs used in the Room Scene with the Network Room Manager above.
|
||||
- [NetworkManagerHUD](NetworkManagerHUD.md)
|
||||
The Network Manager HUD is a quick-start tool to help you start building your multiplayer game straight away, without first having to build a user interface for game creation/connection/joining. It allows you to jump straight into your gameplay programming, and means you can build your own version of these controls later in your development schedule.
|
||||
- [NetworkIdentity](NetworkIdentity.md)
|
||||
|
@ -1,9 +1,9 @@
|
||||
- name: NetworkManager
|
||||
href: NetworkManager.md
|
||||
- name: NetworkLobbyManager
|
||||
href: NetworkLobbyManager.md
|
||||
- name: NetworkLobbyPlayer
|
||||
href: NetworkLobbyPlayer.md
|
||||
- name: NetworkRoomManager
|
||||
href: NetworkRoomManager.md
|
||||
- name: NetworkRoomPlayer
|
||||
href: NetworkRoomPlayer.md
|
||||
- name: NetworkManagerHUD
|
||||
href: NetworkManagerHUD.md
|
||||
- name: NetworkIdentity
|
||||
|
@ -81,11 +81,11 @@ Fix non-player prefabs such as enemies:
|
||||
- Add a new game object and place it at player’s start location
|
||||
- Add the NetworkStartPosition component to the new game object
|
||||
|
||||
## Lobby
|
||||
## Room
|
||||
|
||||
- Create Lobby Scene
|
||||
- Add a new game object to the Scene and rename it to “NetworkLobbyManager”.
|
||||
- Add the NetworkLobbyManager component to the new game object.
|
||||
- Create Room Scene
|
||||
- Add a new game object to the Scene and rename it to “NetworkRoomManager”.
|
||||
- Add the NetworkRoomManager component to the new game object.
|
||||
- Configure the Manager:
|
||||
- Scenes
|
||||
- Prefabs
|
||||
|
@ -49,7 +49,7 @@ Clients can send and receive network messages without being ready, which also me
|
||||
|
||||
## Switching Players
|
||||
|
||||
To replace the player game object for a connection, use `NetworkServer.ReplacePlayerForConnection`. This is useful for restricting the commands that players can issue at certain times, such as in a pregame lobby screen. This function takes the same arguments as `AddPlayerForConnection`, but allows there to already be a player for that connection. The old player game object does not have to be destroyed. The `NetworkLobbyManager` uses this technique to switch from the `NetworkLobbyPlayer` game object to a game play player game object when all the players in the lobby are ready.
|
||||
To replace the player game object for a connection, use `NetworkServer.ReplacePlayerForConnection`. This is useful for restricting the commands that players can issue at certain times, such as in a pregame room screen. This function takes the same arguments as `AddPlayerForConnection`, but allows there to already be a player for that connection. The old player game object does not have to be destroyed. The `NetworkRoomManager` uses this technique to switch from the `NetworkRoomPlayer` game object to a game play player game object when all the players in the room are ready.
|
||||
|
||||
You can also use `ReplacePlayerForConnection` to respawn a player or change the object that represents the player. In some cases it is better to just disable a game object and reset its game attributes on respawn. The following code sample demonstrates how to actually replace the player game object with a new game object:
|
||||
|
||||
@ -76,4 +76,4 @@ If the player game object for a connection is destroyed, then that client cannot
|
||||
|
||||
To use `ReplacePlayerForConnection` you must have the `NetworkConnection` game object for the player’s client to establish the relationship between the game object and the client. This is usually the property `connectionToClient` on the `NetworkBehaviour` class, but if the old player has already been destroyed, then that might not be readily available.
|
||||
|
||||
To find the connection, there are some lists available. If using the `NetworkLobbyManager`, then the lobby players are available in `lobbySlots`. The `NetworkServer` also has lists of `connections`.
|
||||
To find the connection, there are some lists available. If using the `NetworkRoomManager`, then the room players are available in `roomSlots`. The `NetworkServer` also has lists of `connections`.
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Lobby
|
||||
# Room
|
||||
|
||||
General description of Lobby example.
|
||||
General description of Room example.
|
||||
|
@ -13,7 +13,7 @@ First of all, let's have a look at the NetworkManager object in the main scene.
|
||||
When adding the NetworkManager component to a gameobject, a few default settings
|
||||
are already set (**Don't destroy on Load**, **Run in Background**, ...) For
|
||||
playing Pong the maximum number of players is 2, so the setting **Network
|
||||
Info/Max connections** will also be 2. As there are no other scenes (lobby,
|
||||
Info/Max connections** will also be 2. As there are no other scenes (room,
|
||||
online or offline scene) in this sample the properties for **Offline Scene** and
|
||||
**Online Scene** will stay empty.
|
||||
|
||||
|
@ -14,5 +14,5 @@ Mirror includes several small examples to help you learn how to use various feat
|
||||
- [Additive Scenes](AdditiveScenes.md)
|
||||
The Additive Scenes example demonstrates a server additively loading a sub-scene into a main scene at startup, and having a server-only trigger that generates a message to any client whose player enters the trigger zone to also load the sub-scene, and subsequently unload it when they leave the trigger zone. Only players inside the trigger zone can see the objects in the sub-scene. Network Proximity Checker components are key to making this scenario work.
|
||||
|
||||
- [Lobby System](Lobby.md)
|
||||
The Lobby System example demonstrates how to set up a "staging" scene where players assemble before starting a match. When all players are ready, the server sends them all a message to change scenes (along with the server itself) to the actual game play scene so they all come in at once. Includes fully playable game with a character controller where players collect server-spawned prizes for score.
|
||||
- [Room System](Room.md)
|
||||
The Room System example demonstrates how to set up a "staging" scene where players assemble before starting a match. When all players are ready, the server sends them all a message to change scenes (along with the server itself) to the actual game play scene so they all come in at once. Includes fully playable game with a character controller where players collect server-spawned prizes for score.
|
||||
|
@ -2,5 +2,5 @@
|
||||
href: Basic.md
|
||||
- name: Pong
|
||||
href: Pong.md
|
||||
- name: Lobby
|
||||
href: Lobby.md
|
||||
- name: Room
|
||||
href: Room.md
|
||||
|
@ -42,7 +42,7 @@ We've developed a [List Server](https://mirror-networking.com/list-server/) wher
|
||||
|
||||
- Network [Manager](articles/Components/NetworkManager.md) and [HUD](articles/Components/NetworkManagerHUD.md)
|
||||
|
||||
- Network [Lobby Manager](articles/Components/NetworkLobbyManager.md) and [Lobby Player](articles/Components/NetworkLobbyPlayer.md)
|
||||
- Network [Room Manager](articles/Components/NetworkRoomManager.md) and [Room Player](articles/Components/NetworkRoomPlayer.md)
|
||||
|
||||
- Network [Identity](articles/Components/NetworkIdentity.md)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user