Gonna move to server authority
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c12d7cb6cdb799041927819f22a2c931
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: c12d7cb6cdb799041927819f22a2c931
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class CellGUI : MonoBehaviour
|
||||
{
|
||||
public MatchController matchController;
|
||||
public CellValue cellValue;
|
||||
|
||||
[Header("GUI References")]
|
||||
public Image image;
|
||||
public Button button;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public NetworkIdentity playerIdentity;
|
||||
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
matchController.MatchCells.Add(cellValue, this);
|
||||
}
|
||||
|
||||
public void MakePlay()
|
||||
{
|
||||
if (matchController.currentPlayer.isLocalPlayer)
|
||||
matchController.CmdMakePlay(cellValue);
|
||||
}
|
||||
|
||||
public void SetPlayer(NetworkIdentity playerIdentity)
|
||||
{
|
||||
if (playerIdentity != null)
|
||||
{
|
||||
this.playerIdentity = playerIdentity;
|
||||
image.color = this.playerIdentity.isLocalPlayer ? Color.blue : Color.red;
|
||||
button.interactable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playerIdentity = null;
|
||||
image.color = Color.white;
|
||||
button.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class CellGUI : MonoBehaviour
|
||||
{
|
||||
public MatchController matchController;
|
||||
public CellValue cellValue;
|
||||
|
||||
[Header("GUI References")]
|
||||
public Image image;
|
||||
public Button button;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public NetworkIdentity playerIdentity;
|
||||
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
matchController.MatchCells.Add(cellValue, this);
|
||||
}
|
||||
|
||||
public void MakePlay()
|
||||
{
|
||||
if (matchController.currentPlayer.isLocalPlayer)
|
||||
matchController.CmdMakePlay(cellValue);
|
||||
}
|
||||
|
||||
public void SetPlayer(NetworkIdentity playerIdentity)
|
||||
{
|
||||
if (playerIdentity != null)
|
||||
{
|
||||
this.playerIdentity = playerIdentity;
|
||||
image.color = this.playerIdentity.isLocalPlayer ? Color.blue : Color.red;
|
||||
button.interactable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playerIdentity = null;
|
||||
image.color = Color.white;
|
||||
button.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cda2a394a443474689a3c6d6044f7b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 9cda2a394a443474689a3c6d6044f7b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,315 +1,313 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
#pragma warning disable 618
|
||||
[RequireComponent(typeof(NetworkMatchChecker))]
|
||||
#pragma warning restore 618
|
||||
public class MatchController : NetworkBehaviour
|
||||
{
|
||||
internal readonly SyncDictionary<NetworkIdentity, MatchPlayerData> matchPlayerData = new SyncDictionary<NetworkIdentity, MatchPlayerData>();
|
||||
internal readonly Dictionary<CellValue, CellGUI> MatchCells = new Dictionary<CellValue, CellGUI>();
|
||||
|
||||
CellValue boardScore = CellValue.None;
|
||||
bool playAgain = false;
|
||||
|
||||
[Header("GUI References")]
|
||||
public CanvasGroup canvasGroup;
|
||||
public Text gameText;
|
||||
public Button exitButton;
|
||||
public Button playAgainButton;
|
||||
public Text winCountLocal;
|
||||
public Text winCountOpponent;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public CanvasController canvasController;
|
||||
public NetworkIdentity player1;
|
||||
public NetworkIdentity player2;
|
||||
public NetworkIdentity startingPlayer;
|
||||
|
||||
[SyncVar(hook = nameof(UpdateGameUI))]
|
||||
public NetworkIdentity currentPlayer;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
canvasController = FindObjectOfType<CanvasController>();
|
||||
}
|
||||
|
||||
public override void OnStartServer()
|
||||
{
|
||||
StartCoroutine(AddPlayersToMatchController());
|
||||
}
|
||||
|
||||
// For the SyncDictionary to properly fire the update callback, we must
|
||||
// wait a frame before adding the players to the already spawned MatchController
|
||||
IEnumerator AddPlayersToMatchController()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
matchPlayerData.Add(player1, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player1.connectionToClient].playerIndex });
|
||||
matchPlayerData.Add(player2, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player2.connectionToClient].playerIndex });
|
||||
}
|
||||
|
||||
|
||||
public override void OnStartClient()
|
||||
{
|
||||
matchPlayerData.Callback += UpdateWins;
|
||||
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void UpdateGameUI(NetworkIdentity _, NetworkIdentity newPlayerTurn)
|
||||
{
|
||||
if (!newPlayerTurn) return;
|
||||
|
||||
if (newPlayerTurn.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
gameText.text = "Your Turn";
|
||||
gameText.color = Color.blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameText.text = "Their Turn";
|
||||
gameText.color = Color.red;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateWins(SyncDictionary<NetworkIdentity, MatchPlayerData>.Operation op, NetworkIdentity key, MatchPlayerData matchPlayerData)
|
||||
{
|
||||
if (key.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
winCountLocal.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}";
|
||||
}
|
||||
else
|
||||
{
|
||||
winCountOpponent.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}";
|
||||
}
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdMakePlay(CellValue cellValue, NetworkConnectionToClient sender = null)
|
||||
{
|
||||
// If wrong player or cell already taken, ignore
|
||||
if (sender.identity != currentPlayer || MatchCells[cellValue].playerIdentity != null)
|
||||
return;
|
||||
|
||||
MatchCells[cellValue].playerIdentity = currentPlayer;
|
||||
RpcUpdateCell(cellValue, currentPlayer);
|
||||
|
||||
MatchPlayerData mpd = matchPlayerData[currentPlayer];
|
||||
mpd.currentScore = mpd.currentScore | cellValue;
|
||||
matchPlayerData[currentPlayer] = mpd;
|
||||
|
||||
boardScore = boardScore | cellValue;
|
||||
|
||||
if (CheckWinner(mpd.currentScore))
|
||||
{
|
||||
mpd.wins += 1;
|
||||
matchPlayerData[currentPlayer] = mpd;
|
||||
RpcShowWinner(currentPlayer);
|
||||
currentPlayer = null;
|
||||
}
|
||||
else if (boardScore == CellValue.Full)
|
||||
{
|
||||
RpcShowWinner(null);
|
||||
currentPlayer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set currentPlayer SyncVar so clients know whose turn it is
|
||||
currentPlayer = currentPlayer == player1 ? player2 : player1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CheckWinner(CellValue currentScore)
|
||||
{
|
||||
if ((currentScore & CellValue.TopRow) == CellValue.TopRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.MidRow) == CellValue.MidRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.BotRow) == CellValue.BotRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.LeftCol) == CellValue.LeftCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.MidCol) == CellValue.MidCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.RightCol) == CellValue.RightCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.Diag1) == CellValue.Diag1)
|
||||
return true;
|
||||
if ((currentScore & CellValue.Diag2) == CellValue.Diag2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcUpdateCell(CellValue cellValue, NetworkIdentity player)
|
||||
{
|
||||
MatchCells[cellValue].SetPlayer(player);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcShowWinner(NetworkIdentity winner)
|
||||
{
|
||||
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.GetComponent<Button>().interactable = false;
|
||||
|
||||
if (winner == null)
|
||||
{
|
||||
gameText.text = "Draw!";
|
||||
gameText.color = Color.yellow;
|
||||
}
|
||||
else if (winner.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
gameText.text = "Winner!";
|
||||
gameText.color = Color.blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameText.text = "Loser!";
|
||||
gameText.color = Color.red;
|
||||
}
|
||||
exitButton.gameObject.SetActive(true);
|
||||
playAgainButton.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
// Assigned in inspector to ReplayButton::OnClick
|
||||
[Client]
|
||||
public void RequestPlayAgain()
|
||||
{
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
CmdPlayAgain();
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdPlayAgain(NetworkConnectionToClient sender = null)
|
||||
{
|
||||
if (!playAgain)
|
||||
{
|
||||
playAgain = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
playAgain = false;
|
||||
RestartGame();
|
||||
}
|
||||
}
|
||||
|
||||
[Server]
|
||||
public void RestartGame()
|
||||
{
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.SetPlayer(null);
|
||||
|
||||
boardScore = CellValue.None;
|
||||
|
||||
NetworkIdentity[] keys = new NetworkIdentity[matchPlayerData.Keys.Count];
|
||||
matchPlayerData.Keys.CopyTo(keys, 0);
|
||||
|
||||
foreach (NetworkIdentity identity in keys)
|
||||
{
|
||||
MatchPlayerData mpd = matchPlayerData[identity];
|
||||
mpd.currentScore = CellValue.None;
|
||||
matchPlayerData[identity] = mpd;
|
||||
}
|
||||
|
||||
RpcRestartGame();
|
||||
|
||||
startingPlayer = startingPlayer == player1 ? player2 : player1;
|
||||
currentPlayer = startingPlayer;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcRestartGame()
|
||||
{
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.SetPlayer(null);
|
||||
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Assigned in inspector to BackButton::OnClick
|
||||
[Client]
|
||||
public void RequestExitGame()
|
||||
{
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
CmdRequestExitGame();
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdRequestExitGame(NetworkConnectionToClient sender = null)
|
||||
{
|
||||
StartCoroutine(ServerEndMatch(sender, false));
|
||||
}
|
||||
|
||||
public void OnPlayerDisconnected(NetworkConnection conn)
|
||||
{
|
||||
// Check that the disconnecting client is a player in this match
|
||||
if (player1 == conn.identity || player2 == conn.identity)
|
||||
{
|
||||
StartCoroutine(ServerEndMatch(conn, true));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator ServerEndMatch(NetworkConnection conn, bool disconnected)
|
||||
{
|
||||
canvasController.OnPlayerDisconnected -= OnPlayerDisconnected;
|
||||
|
||||
RpcExitGame();
|
||||
|
||||
// Skip a frame so the message goes out ahead of object destruction
|
||||
yield return null;
|
||||
|
||||
// Mirror will clean up the disconnecting client so we only need to clean up the other remaining client.
|
||||
// If both players are just returning to the Lobby, we need to remove both connection Players
|
||||
|
||||
if (!disconnected)
|
||||
{
|
||||
NetworkServer.RemovePlayerForConnection(player1.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player1.connectionToClient);
|
||||
|
||||
NetworkServer.RemovePlayerForConnection(player2.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player2.connectionToClient);
|
||||
}
|
||||
else if (conn == player1.connectionToClient)
|
||||
{
|
||||
// player1 has disconnected - send player2 back to Lobby
|
||||
NetworkServer.RemovePlayerForConnection(player2.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player2.connectionToClient);
|
||||
}
|
||||
else if (conn == player2.connectionToClient)
|
||||
{
|
||||
// player2 has disconnected - send player1 back to Lobby
|
||||
NetworkServer.RemovePlayerForConnection(player1.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player1.connectionToClient);
|
||||
}
|
||||
|
||||
// Skip a frame to allow the Removal(s) to complete
|
||||
yield return null;
|
||||
|
||||
// Send latest match list
|
||||
canvasController.SendMatchList();
|
||||
|
||||
NetworkServer.Destroy(gameObject);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcExitGame()
|
||||
{
|
||||
canvasController.OnMatchEnded();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
[RequireComponent(typeof(NetworkMatch))]
|
||||
public class MatchController : NetworkBehaviour
|
||||
{
|
||||
internal readonly SyncDictionary<NetworkIdentity, MatchPlayerData> matchPlayerData = new SyncDictionary<NetworkIdentity, MatchPlayerData>();
|
||||
internal readonly Dictionary<CellValue, CellGUI> MatchCells = new Dictionary<CellValue, CellGUI>();
|
||||
|
||||
CellValue boardScore = CellValue.None;
|
||||
bool playAgain = false;
|
||||
|
||||
[Header("GUI References")]
|
||||
public CanvasGroup canvasGroup;
|
||||
public Text gameText;
|
||||
public Button exitButton;
|
||||
public Button playAgainButton;
|
||||
public Text winCountLocal;
|
||||
public Text winCountOpponent;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public CanvasController canvasController;
|
||||
public NetworkIdentity player1;
|
||||
public NetworkIdentity player2;
|
||||
public NetworkIdentity startingPlayer;
|
||||
|
||||
[SyncVar(hook = nameof(UpdateGameUI))]
|
||||
public NetworkIdentity currentPlayer;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
canvasController = FindObjectOfType<CanvasController>();
|
||||
}
|
||||
|
||||
public override void OnStartServer()
|
||||
{
|
||||
StartCoroutine(AddPlayersToMatchController());
|
||||
}
|
||||
|
||||
// For the SyncDictionary to properly fire the update callback, we must
|
||||
// wait a frame before adding the players to the already spawned MatchController
|
||||
IEnumerator AddPlayersToMatchController()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
matchPlayerData.Add(player1, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player1.connectionToClient].playerIndex });
|
||||
matchPlayerData.Add(player2, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player2.connectionToClient].playerIndex });
|
||||
}
|
||||
|
||||
|
||||
public override void OnStartClient()
|
||||
{
|
||||
matchPlayerData.Callback += UpdateWins;
|
||||
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void UpdateGameUI(NetworkIdentity _, NetworkIdentity newPlayerTurn)
|
||||
{
|
||||
if (!newPlayerTurn) return;
|
||||
|
||||
if (newPlayerTurn.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
gameText.text = "Your Turn";
|
||||
gameText.color = Color.blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameText.text = "Their Turn";
|
||||
gameText.color = Color.red;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateWins(SyncDictionary<NetworkIdentity, MatchPlayerData>.Operation op, NetworkIdentity key, MatchPlayerData matchPlayerData)
|
||||
{
|
||||
if (key.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
winCountLocal.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}";
|
||||
}
|
||||
else
|
||||
{
|
||||
winCountOpponent.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}";
|
||||
}
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdMakePlay(CellValue cellValue, NetworkConnectionToClient sender = null)
|
||||
{
|
||||
// If wrong player or cell already taken, ignore
|
||||
if (sender.identity != currentPlayer || MatchCells[cellValue].playerIdentity != null)
|
||||
return;
|
||||
|
||||
MatchCells[cellValue].playerIdentity = currentPlayer;
|
||||
RpcUpdateCell(cellValue, currentPlayer);
|
||||
|
||||
MatchPlayerData mpd = matchPlayerData[currentPlayer];
|
||||
mpd.currentScore = mpd.currentScore | cellValue;
|
||||
matchPlayerData[currentPlayer] = mpd;
|
||||
|
||||
boardScore = boardScore | cellValue;
|
||||
|
||||
if (CheckWinner(mpd.currentScore))
|
||||
{
|
||||
mpd.wins += 1;
|
||||
matchPlayerData[currentPlayer] = mpd;
|
||||
RpcShowWinner(currentPlayer);
|
||||
currentPlayer = null;
|
||||
}
|
||||
else if (boardScore == CellValue.Full)
|
||||
{
|
||||
RpcShowWinner(null);
|
||||
currentPlayer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set currentPlayer SyncVar so clients know whose turn it is
|
||||
currentPlayer = currentPlayer == player1 ? player2 : player1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CheckWinner(CellValue currentScore)
|
||||
{
|
||||
if ((currentScore & CellValue.TopRow) == CellValue.TopRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.MidRow) == CellValue.MidRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.BotRow) == CellValue.BotRow)
|
||||
return true;
|
||||
if ((currentScore & CellValue.LeftCol) == CellValue.LeftCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.MidCol) == CellValue.MidCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.RightCol) == CellValue.RightCol)
|
||||
return true;
|
||||
if ((currentScore & CellValue.Diag1) == CellValue.Diag1)
|
||||
return true;
|
||||
if ((currentScore & CellValue.Diag2) == CellValue.Diag2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcUpdateCell(CellValue cellValue, NetworkIdentity player)
|
||||
{
|
||||
MatchCells[cellValue].SetPlayer(player);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcShowWinner(NetworkIdentity winner)
|
||||
{
|
||||
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.GetComponent<Button>().interactable = false;
|
||||
|
||||
if (winner == null)
|
||||
{
|
||||
gameText.text = "Draw!";
|
||||
gameText.color = Color.yellow;
|
||||
}
|
||||
else if (winner.gameObject.GetComponent<NetworkIdentity>().isLocalPlayer)
|
||||
{
|
||||
gameText.text = "Winner!";
|
||||
gameText.color = Color.blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameText.text = "Loser!";
|
||||
gameText.color = Color.red;
|
||||
}
|
||||
exitButton.gameObject.SetActive(true);
|
||||
playAgainButton.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
// Assigned in inspector to ReplayButton::OnClick
|
||||
[Client]
|
||||
public void RequestPlayAgain()
|
||||
{
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
CmdPlayAgain();
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdPlayAgain(NetworkConnectionToClient sender = null)
|
||||
{
|
||||
if (!playAgain)
|
||||
{
|
||||
playAgain = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
playAgain = false;
|
||||
RestartGame();
|
||||
}
|
||||
}
|
||||
|
||||
[Server]
|
||||
public void RestartGame()
|
||||
{
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.SetPlayer(null);
|
||||
|
||||
boardScore = CellValue.None;
|
||||
|
||||
NetworkIdentity[] keys = new NetworkIdentity[matchPlayerData.Keys.Count];
|
||||
matchPlayerData.Keys.CopyTo(keys, 0);
|
||||
|
||||
foreach (NetworkIdentity identity in keys)
|
||||
{
|
||||
MatchPlayerData mpd = matchPlayerData[identity];
|
||||
mpd.currentScore = CellValue.None;
|
||||
matchPlayerData[identity] = mpd;
|
||||
}
|
||||
|
||||
RpcRestartGame();
|
||||
|
||||
startingPlayer = startingPlayer == player1 ? player2 : player1;
|
||||
currentPlayer = startingPlayer;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcRestartGame()
|
||||
{
|
||||
foreach (CellGUI cellGUI in MatchCells.Values)
|
||||
cellGUI.SetPlayer(null);
|
||||
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Assigned in inspector to BackButton::OnClick
|
||||
[Client]
|
||||
public void RequestExitGame()
|
||||
{
|
||||
exitButton.gameObject.SetActive(false);
|
||||
playAgainButton.gameObject.SetActive(false);
|
||||
CmdRequestExitGame();
|
||||
}
|
||||
|
||||
[Command(requiresAuthority = false)]
|
||||
public void CmdRequestExitGame(NetworkConnectionToClient sender = null)
|
||||
{
|
||||
StartCoroutine(ServerEndMatch(sender, false));
|
||||
}
|
||||
|
||||
public void OnPlayerDisconnected(NetworkConnection conn)
|
||||
{
|
||||
// Check that the disconnecting client is a player in this match
|
||||
if (player1 == conn.identity || player2 == conn.identity)
|
||||
{
|
||||
StartCoroutine(ServerEndMatch(conn, true));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator ServerEndMatch(NetworkConnection conn, bool disconnected)
|
||||
{
|
||||
canvasController.OnPlayerDisconnected -= OnPlayerDisconnected;
|
||||
|
||||
RpcExitGame();
|
||||
|
||||
// Skip a frame so the message goes out ahead of object destruction
|
||||
yield return null;
|
||||
|
||||
// Mirror will clean up the disconnecting client so we only need to clean up the other remaining client.
|
||||
// If both players are just returning to the Lobby, we need to remove both connection Players
|
||||
|
||||
if (!disconnected)
|
||||
{
|
||||
NetworkServer.RemovePlayerForConnection(player1.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player1.connectionToClient);
|
||||
|
||||
NetworkServer.RemovePlayerForConnection(player2.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player2.connectionToClient);
|
||||
}
|
||||
else if (conn == player1.connectionToClient)
|
||||
{
|
||||
// player1 has disconnected - send player2 back to Lobby
|
||||
NetworkServer.RemovePlayerForConnection(player2.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player2.connectionToClient);
|
||||
}
|
||||
else if (conn == player2.connectionToClient)
|
||||
{
|
||||
// player2 has disconnected - send player1 back to Lobby
|
||||
NetworkServer.RemovePlayerForConnection(player1.connectionToClient, true);
|
||||
CanvasController.waitingConnections.Add(player1.connectionToClient);
|
||||
}
|
||||
|
||||
// Skip a frame to allow the Removal(s) to complete
|
||||
yield return null;
|
||||
|
||||
// Send latest match list
|
||||
canvasController.SendMatchList();
|
||||
|
||||
NetworkServer.Destroy(gameObject);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void RpcExitGame()
|
||||
{
|
||||
canvasController.OnMatchEnded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ccb1dd1fc7cc624e9bff1d0d7a5c741
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 9ccb1dd1fc7cc624e9bff1d0d7a5c741
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class MatchGUI : MonoBehaviour
|
||||
{
|
||||
Guid matchId;
|
||||
|
||||
[Header("GUI Elements")]
|
||||
public Image image;
|
||||
public Toggle toggleButton;
|
||||
public Text matchName;
|
||||
public Text playerCount;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public CanvasController canvasController;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
canvasController = FindObjectOfType<CanvasController>();
|
||||
toggleButton.onValueChanged.AddListener(delegate { OnToggleClicked(); });
|
||||
}
|
||||
|
||||
public void OnToggleClicked()
|
||||
{
|
||||
canvasController.SelectMatch(toggleButton.isOn ? matchId : Guid.Empty);
|
||||
image.color = toggleButton.isOn ? new Color(0f, 1f, 0f, 0.5f) : new Color(1f, 1f, 1f, 0.2f);
|
||||
}
|
||||
|
||||
public Guid GetMatchId()
|
||||
{
|
||||
return matchId;
|
||||
}
|
||||
|
||||
public void SetMatchInfo(MatchInfo infos)
|
||||
{
|
||||
matchId = infos.matchId;
|
||||
matchName.text = "Match " + infos.matchId.ToString().Substring(0, 8);
|
||||
playerCount.text = infos.players + " / " + infos.maxPlayers;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class MatchGUI : MonoBehaviour
|
||||
{
|
||||
Guid matchId;
|
||||
|
||||
[Header("GUI Elements")]
|
||||
public Image image;
|
||||
public Toggle toggleButton;
|
||||
public Text matchName;
|
||||
public Text playerCount;
|
||||
|
||||
[Header("Diagnostics - Do Not Modify")]
|
||||
public CanvasController canvasController;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
canvasController = FindObjectOfType<CanvasController>();
|
||||
toggleButton.onValueChanged.AddListener(delegate { OnToggleClicked(); });
|
||||
}
|
||||
|
||||
public void OnToggleClicked()
|
||||
{
|
||||
canvasController.SelectMatch(toggleButton.isOn ? matchId : Guid.Empty);
|
||||
image.color = toggleButton.isOn ? new Color(0f, 1f, 0f, 0.5f) : new Color(1f, 1f, 1f, 0.2f);
|
||||
}
|
||||
|
||||
public Guid GetMatchId()
|
||||
{
|
||||
return matchId;
|
||||
}
|
||||
|
||||
public void SetMatchInfo(MatchInfo infos)
|
||||
{
|
||||
matchId = infos.matchId;
|
||||
matchName.text = $"Match {infos.matchId.ToString().Substring(0, 8)}";
|
||||
playerCount.text = $"{infos.players} / {infos.maxPlayers}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e875a237ce12c3145b20f17222f10b68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: e875a237ce12c3145b20f17222f10b68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,118 +1,118 @@
|
||||
using System;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Match message to be sent to the server
|
||||
/// </summary>
|
||||
public struct ServerMatchMessage : NetworkMessage
|
||||
{
|
||||
public ServerMatchOperation serverMatchOperation;
|
||||
public Guid matchId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match message to be sent to the client
|
||||
/// </summary>
|
||||
public struct ClientMatchMessage : NetworkMessage
|
||||
{
|
||||
public ClientMatchOperation clientMatchOperation;
|
||||
public Guid matchId;
|
||||
public MatchInfo[] matchInfos;
|
||||
public PlayerInfo[] playerInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a match
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct MatchInfo
|
||||
{
|
||||
public Guid matchId;
|
||||
public byte players;
|
||||
public byte maxPlayers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a player
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct PlayerInfo
|
||||
{
|
||||
public int playerIndex;
|
||||
public bool ready;
|
||||
public Guid matchId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct MatchPlayerData
|
||||
{
|
||||
public int playerIndex;
|
||||
public int wins;
|
||||
public CellValue currentScore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match operation to execute on the server
|
||||
/// </summary>
|
||||
public enum ServerMatchOperation : byte
|
||||
{
|
||||
None,
|
||||
Create,
|
||||
Cancel,
|
||||
Start,
|
||||
Join,
|
||||
Leave,
|
||||
Ready
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match operation to execute on the client
|
||||
/// </summary>
|
||||
public enum ClientMatchOperation : byte
|
||||
{
|
||||
None,
|
||||
List,
|
||||
Created,
|
||||
Cancelled,
|
||||
Joined,
|
||||
Departed,
|
||||
UpdateRoom,
|
||||
Started
|
||||
}
|
||||
|
||||
|
||||
// A1 | B1 | C1
|
||||
// ---+----+---
|
||||
// A2 | B2 | C2
|
||||
// ---+----+---
|
||||
// A3 | B3 | C3
|
||||
|
||||
[Flags]
|
||||
public enum CellValue : ushort
|
||||
{
|
||||
None,
|
||||
A1 = 1 << 0,
|
||||
B1 = 1 << 1,
|
||||
C1 = 1 << 2,
|
||||
A2 = 1 << 3,
|
||||
B2 = 1 << 4,
|
||||
C2 = 1 << 5,
|
||||
A3 = 1 << 6,
|
||||
B3 = 1 << 7,
|
||||
C3 = 1 << 8,
|
||||
|
||||
// winning combinations
|
||||
TopRow = A1 + B1 + C1,
|
||||
MidRow = A2 + B2 + C2,
|
||||
BotRow = A3 + B3 + C3,
|
||||
LeftCol = A1 + A2 + A3,
|
||||
MidCol = B1 + B2 + B3,
|
||||
RightCol = C1 + C2 + C3,
|
||||
Diag1 = A1 + B2 + C3,
|
||||
Diag2 = A3 + B2 + C1,
|
||||
|
||||
// board is full (winner / draw)
|
||||
Full = TopRow + MidRow + BotRow
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Match message to be sent to the server
|
||||
/// </summary>
|
||||
public struct ServerMatchMessage : NetworkMessage
|
||||
{
|
||||
public ServerMatchOperation serverMatchOperation;
|
||||
public Guid matchId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match message to be sent to the client
|
||||
/// </summary>
|
||||
public struct ClientMatchMessage : NetworkMessage
|
||||
{
|
||||
public ClientMatchOperation clientMatchOperation;
|
||||
public Guid matchId;
|
||||
public MatchInfo[] matchInfos;
|
||||
public PlayerInfo[] playerInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a match
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct MatchInfo
|
||||
{
|
||||
public Guid matchId;
|
||||
public byte players;
|
||||
public byte maxPlayers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a player
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct PlayerInfo
|
||||
{
|
||||
public int playerIndex;
|
||||
public bool ready;
|
||||
public Guid matchId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct MatchPlayerData
|
||||
{
|
||||
public int playerIndex;
|
||||
public int wins;
|
||||
public CellValue currentScore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match operation to execute on the server
|
||||
/// </summary>
|
||||
public enum ServerMatchOperation : byte
|
||||
{
|
||||
None,
|
||||
Create,
|
||||
Cancel,
|
||||
Start,
|
||||
Join,
|
||||
Leave,
|
||||
Ready
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match operation to execute on the client
|
||||
/// </summary>
|
||||
public enum ClientMatchOperation : byte
|
||||
{
|
||||
None,
|
||||
List,
|
||||
Created,
|
||||
Cancelled,
|
||||
Joined,
|
||||
Departed,
|
||||
UpdateRoom,
|
||||
Started
|
||||
}
|
||||
|
||||
|
||||
// A1 | B1 | C1
|
||||
// ---+----+---
|
||||
// A2 | B2 | C2
|
||||
// ---+----+---
|
||||
// A3 | B3 | C3
|
||||
|
||||
[Flags]
|
||||
public enum CellValue : ushort
|
||||
{
|
||||
None,
|
||||
A1 = 1 << 0,
|
||||
B1 = 1 << 1,
|
||||
C1 = 1 << 2,
|
||||
A2 = 1 << 3,
|
||||
B2 = 1 << 4,
|
||||
C2 = 1 << 5,
|
||||
A3 = 1 << 6,
|
||||
B3 = 1 << 7,
|
||||
C3 = 1 << 8,
|
||||
|
||||
// winning combinations
|
||||
TopRow = A1 + B1 + C1,
|
||||
MidRow = A2 + B2 + C2,
|
||||
BotRow = A3 + B3 + C3,
|
||||
LeftCol = A1 + A2 + A3,
|
||||
MidCol = B1 + B2 + B3,
|
||||
RightCol = C1 + C2 + C3,
|
||||
Diag1 = A1 + B2 + C3,
|
||||
Diag2 = A3 + B2 + C1,
|
||||
|
||||
// board is full (winner / draw)
|
||||
Full = TopRow + MidRow + BotRow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a98b377d8481e52449b996e45a015b8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: a98b377d8481e52449b996e45a015b8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,125 +1,125 @@
|
||||
using UnityEngine;
|
||||
|
||||
/*
|
||||
Documentation: https://mirror-networking.gitbook.io/docs/components/network-manager
|
||||
API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkManager.html
|
||||
*/
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class MatchNetworkManager : NetworkManager
|
||||
{
|
||||
[Header("Match GUI")]
|
||||
public GameObject canvas;
|
||||
public CanvasController canvasController;
|
||||
|
||||
#region Unity Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Runs on both Server and Client
|
||||
/// Networking is NOT initialized when this fires
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
canvasController.InitializeData();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server System Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called on the server when a client is ready.
|
||||
/// <para>The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection from client.</param>
|
||||
public override void OnServerReady(NetworkConnection conn)
|
||||
{
|
||||
base.OnServerReady(conn);
|
||||
canvasController.OnServerReady(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on the server when a client disconnects.
|
||||
/// <para>This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection from client.</param>
|
||||
public override void OnServerDisconnect(NetworkConnection conn)
|
||||
{
|
||||
canvasController.OnServerDisconnect(conn);
|
||||
base.OnServerDisconnect(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client System Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called on the client when connected to a server.
|
||||
/// <para>The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection to the server.</param>
|
||||
public override void OnClientConnect(NetworkConnection conn)
|
||||
{
|
||||
base.OnClientConnect(conn);
|
||||
canvasController.OnClientConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on clients when disconnected from a server.
|
||||
/// <para>This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection to the server.</param>
|
||||
public override void OnClientDisconnect(NetworkConnection conn)
|
||||
{
|
||||
canvasController.OnClientDisconnect();
|
||||
base.OnClientDisconnect(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Start & Stop Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// This is invoked when a server is started - including when a host is started.
|
||||
/// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
|
||||
/// </summary>
|
||||
public override void OnStartServer()
|
||||
{
|
||||
if (mode == NetworkManagerMode.ServerOnly)
|
||||
canvas.SetActive(true);
|
||||
|
||||
canvasController.OnStartServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is invoked when the client is started.
|
||||
/// </summary>
|
||||
public override void OnStartClient()
|
||||
{
|
||||
canvas.SetActive(true);
|
||||
canvasController.OnStartClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when a server is stopped - including when a host is stopped.
|
||||
/// </summary>
|
||||
public override void OnStopServer()
|
||||
{
|
||||
canvasController.OnStopServer();
|
||||
canvas.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when a client is stopped.
|
||||
/// </summary>
|
||||
public override void OnStopClient()
|
||||
{
|
||||
canvasController.OnStopClient();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
using UnityEngine;
|
||||
|
||||
/*
|
||||
Documentation: https://mirror-networking.gitbook.io/docs/components/network-manager
|
||||
API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkManager.html
|
||||
*/
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class MatchNetworkManager : NetworkManager
|
||||
{
|
||||
[Header("Match GUI")]
|
||||
public GameObject canvas;
|
||||
public CanvasController canvasController;
|
||||
|
||||
#region Unity Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Runs on both Server and Client
|
||||
/// Networking is NOT initialized when this fires
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
canvasController.InitializeData();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server System Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called on the server when a client is ready.
|
||||
/// <para>The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection from client.</param>
|
||||
public override void OnServerReady(NetworkConnection conn)
|
||||
{
|
||||
base.OnServerReady(conn);
|
||||
canvasController.OnServerReady(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on the server when a client disconnects.
|
||||
/// <para>This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection from client.</param>
|
||||
public override void OnServerDisconnect(NetworkConnection conn)
|
||||
{
|
||||
canvasController.OnServerDisconnect(conn);
|
||||
base.OnServerDisconnect(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client System Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Called on the client when connected to a server.
|
||||
/// <para>The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection to the server.</param>
|
||||
public override void OnClientConnect(NetworkConnection conn)
|
||||
{
|
||||
base.OnClientConnect(conn);
|
||||
canvasController.OnClientConnect(conn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on clients when disconnected from a server.
|
||||
/// <para>This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects.</para>
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection to the server.</param>
|
||||
public override void OnClientDisconnect(NetworkConnection conn)
|
||||
{
|
||||
canvasController.OnClientDisconnect();
|
||||
base.OnClientDisconnect(conn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Start & Stop Callbacks
|
||||
|
||||
/// <summary>
|
||||
/// This is invoked when a server is started - including when a host is started.
|
||||
/// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
|
||||
/// </summary>
|
||||
public override void OnStartServer()
|
||||
{
|
||||
if (mode == NetworkManagerMode.ServerOnly)
|
||||
canvas.SetActive(true);
|
||||
|
||||
canvasController.OnStartServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is invoked when the client is started.
|
||||
/// </summary>
|
||||
public override void OnStartClient()
|
||||
{
|
||||
canvas.SetActive(true);
|
||||
canvasController.OnStartClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when a server is stopped - including when a host is stopped.
|
||||
/// </summary>
|
||||
public override void OnStopServer()
|
||||
{
|
||||
canvasController.OnStopServer();
|
||||
canvas.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when a client is stopped.
|
||||
/// </summary>
|
||||
public override void OnStopClient()
|
||||
{
|
||||
canvasController.OnStopClient();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b15c78bb8ab8da42a94aa0bc3081814
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 0b15c78bb8ab8da42a94aa0bc3081814
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class PlayerGUI : MonoBehaviour
|
||||
{
|
||||
public Text playerName;
|
||||
|
||||
public void SetPlayerInfo(PlayerInfo info)
|
||||
{
|
||||
playerName.text = "Player " + info.playerIndex;
|
||||
playerName.color = info.ready ? Color.green : Color.red;
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class PlayerGUI : MonoBehaviour
|
||||
{
|
||||
public Text playerName;
|
||||
|
||||
public void SetPlayerInfo(PlayerInfo info)
|
||||
{
|
||||
playerName.text = $"Player {info.playerIndex}";
|
||||
playerName.color = info.ready ? Color.green : Color.red;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f61e9bc3715eb904b91222a5526f63d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: f61e9bc3715eb904b91222a5526f63d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class RoomGUI : MonoBehaviour
|
||||
{
|
||||
public GameObject playerList;
|
||||
public GameObject playerPrefab;
|
||||
public GameObject cancelButton;
|
||||
public GameObject leaveButton;
|
||||
public Button startButton;
|
||||
public bool owner;
|
||||
|
||||
public void RefreshRoomPlayers(PlayerInfo[] playerInfos)
|
||||
{
|
||||
// Debug.Log($"RefreshRoomPlayers: {playerInfos.Length} playerInfos");
|
||||
|
||||
foreach (Transform child in playerList.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
startButton.interactable = false;
|
||||
bool everyoneReady = true;
|
||||
|
||||
foreach (PlayerInfo playerInfo in playerInfos)
|
||||
{
|
||||
GameObject newPlayer = Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
|
||||
newPlayer.transform.SetParent(playerList.transform, false);
|
||||
newPlayer.GetComponent<PlayerGUI>().SetPlayerInfo(playerInfo);
|
||||
if (!playerInfo.ready)
|
||||
{
|
||||
everyoneReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
startButton.interactable = everyoneReady && owner && (playerInfos.Length > 1);
|
||||
}
|
||||
|
||||
public void SetOwner(bool owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
cancelButton.SetActive(owner);
|
||||
leaveButton.SetActive(!owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Mirror.Examples.MultipleMatch
|
||||
{
|
||||
public class RoomGUI : MonoBehaviour
|
||||
{
|
||||
public GameObject playerList;
|
||||
public GameObject playerPrefab;
|
||||
public GameObject cancelButton;
|
||||
public GameObject leaveButton;
|
||||
public Button startButton;
|
||||
public bool owner;
|
||||
|
||||
public void RefreshRoomPlayers(PlayerInfo[] playerInfos)
|
||||
{
|
||||
// Debug.Log($"RefreshRoomPlayers: {playerInfos.Length} playerInfos");
|
||||
|
||||
foreach (Transform child in playerList.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
startButton.interactable = false;
|
||||
bool everyoneReady = true;
|
||||
|
||||
foreach (PlayerInfo playerInfo in playerInfos)
|
||||
{
|
||||
GameObject newPlayer = Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
|
||||
newPlayer.transform.SetParent(playerList.transform, false);
|
||||
newPlayer.GetComponent<PlayerGUI>().SetPlayerInfo(playerInfo);
|
||||
if (!playerInfo.ready)
|
||||
{
|
||||
everyoneReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
startButton.interactable = everyoneReady && owner && (playerInfos.Length > 1);
|
||||
}
|
||||
|
||||
public void SetOwner(bool owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
cancelButton.SetActive(owner);
|
||||
leaveButton.SetActive(!owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc0f113afba9a074b9a3e4fb56f16abb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: fc0f113afba9a074b9a3e4fb56f16abb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData: ''
|
||||
assetBundleName: ''
|
||||
assetBundleVariant: ''
|
||||
|
||||
Reference in New Issue
Block a user