Rewrote Networking and Base Lobby Created

- Rewrote networking based on tutorials from MLAPI Demo Project and
  Dapper Dino
- Created Lobby UI based on the turorial from Dapper Dino
- Linked Existing UI into using the new networking
- Modified Lobby Settings to only allow 3 players
- Added Field for players to enter their player name
This commit is contained in:
2021-10-15 16:01:18 -05:00
parent fdf3541135
commit db5b10ef47
39 changed files with 4041 additions and 480 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bac1def4c30048140986167189190078
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class LobbyPlayerCard : MonoBehaviour {
[Header("Panels")]
[SerializeField] private GameObject waitingForPlayerPanel;
[SerializeField] private GameObject playerDataPanel;
[Header("Data Display")]
[SerializeField] private TMP_Text playerDisplayNameText;
[SerializeField] private Image selectedCharacterImage;
[SerializeField] private Toggle isReadyToggle;
public void UpdateDisplay(LobbyPlayerState lobbyPlayerState)
{
playerDisplayNameText.text = lobbyPlayerState.PlayerName;
isReadyToggle.isOn = lobbyPlayerState.IsReady;
waitingForPlayerPanel.SetActive(false);
playerDataPanel.SetActive(true);
}
public void DisableDisplay()
{
waitingForPlayerPanel.SetActive(true);
playerDataPanel.SetActive(false);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 311c1a64d12df464ab0b856d2aa3e5ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
using MLAPI.Serialization;
public struct LobbyPlayerState : INetworkSerializable {
public ulong ClientId;
public string PlayerName;
public bool IsReady;
public LobbyPlayerState(ulong clientId, string playerName, bool isReady)
{
ClientId = clientId;
PlayerName = playerName;
IsReady = isReady;
}
public void NetworkSerialize(NetworkSerializer serializer)
{
serializer.Serialize(ref ClientId);
serializer.Serialize(ref PlayerName);
serializer.Serialize(ref IsReady);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81e16a8360aa6c94094061211aef3e66
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,155 @@
using System;
using MLAPI;
using MLAPI.Connection;
using MLAPI.Messaging;
using MLAPI.NetworkVariable.Collections;
using UnityEngine;
using UnityEngine.UI;
public class LobbyUI : NetworkBehaviour {
[Header("References")]
[SerializeField] private LobbyPlayerCard[] lobbyPlayerCards;
[SerializeField] private Button startGameButton;
private NetworkList<LobbyPlayerState> lobbyPlayers = new NetworkList<LobbyPlayerState>();
public override void NetworkStart()
{
if (IsClient)
{
lobbyPlayers.OnListChanged += HandleLobbyPlayersStateChanged;
}
if (IsServer)
{
startGameButton.gameObject.SetActive(true);
NetworkManager.Singleton.OnClientConnectedCallback += HandleClientConnected;
NetworkManager.Singleton.OnClientDisconnectCallback += HandleClientDisconnect;
foreach (NetworkClient client in NetworkManager.Singleton.ConnectedClientsList)
{
HandleClientConnected(client.ClientId);
}
}
}
private void OnDestroy()
{
lobbyPlayers.OnListChanged -= HandleLobbyPlayersStateChanged;
if (NetworkManager.Singleton)
{
NetworkManager.Singleton.OnClientConnectedCallback -= HandleClientConnected;
NetworkManager.Singleton.OnClientDisconnectCallback -= HandleClientDisconnect;
}
}
private bool IsEveryoneReady()
{
// Make sure there is 3 players in the lobby
if (lobbyPlayers.Count != 3)
{
return false;
}
// TODO: Need to add a check to make sure that 2 are runners and 1 is king
foreach (var player in lobbyPlayers)
{
if (!player.IsReady)
{
return false;
}
}
return true;
}
private void HandleClientConnected(ulong clientId)
{
var playerData = ServerGameNetPortal.Instance.GetPlayerData(clientId);
if (!playerData.HasValue) { return; }
lobbyPlayers.Add(new LobbyPlayerState(
clientId,
playerData.Value.PlayerName,
false
));
}
private void HandleClientDisconnect(ulong clientId)
{
for (int i = 0; i < lobbyPlayers.Count; i++)
{
if (lobbyPlayers[i].ClientId == clientId)
{
lobbyPlayers.RemoveAt(i);
break;
}
}
}
[ServerRpc(RequireOwnership = false)]
private void ToggleReadyServerRpc(ServerRpcParams serverRpcParams = default)
{
for (int i = 0; i < lobbyPlayers.Count; i++)
{
if (lobbyPlayers[i].ClientId == serverRpcParams.Receive.SenderClientId)
{
lobbyPlayers[i] = new LobbyPlayerState(
lobbyPlayers[i].ClientId,
lobbyPlayers[i].PlayerName,
!lobbyPlayers[i].IsReady
);
}
}
}
[ServerRpc(RequireOwnership = false)]
private void StartGameServerRpc(ServerRpcParams serverRpcParams = default)
{
if (serverRpcParams.Receive.SenderClientId != NetworkManager.Singleton.LocalClientId) { return; }
if (!IsEveryoneReady()) { return; }
ServerGameNetPortal.Instance.StartGame();
}
public void OnLeaveClicked()
{
GameNetPortal.Instance.RequestDisconnect();
}
public void OnReadyClicked()
{
ToggleReadyServerRpc();
}
public void OnStartGameClicked()
{
StartGameServerRpc();
}
private void HandleLobbyPlayersStateChanged(NetworkListEvent<LobbyPlayerState> lobbyState)
{
for (int i = 0; i < lobbyPlayerCards.Length; i++)
{
if (lobbyPlayers.Count > i)
{
lobbyPlayerCards[i].UpdateDisplay(lobbyPlayers[i]);
}
else
{
lobbyPlayerCards[i].DisableDisplay();
}
}
if(IsHost)
{
startGameButton.interactable = IsEveryoneReady();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea8a020e40c2c2443810c67a957f44e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 791d1f5615272234d89da9396541ce1d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,106 @@
using MLAPI;
using System.Collections;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ConnectButtons : MonoBehaviour {
// The IP Used to connect to the dedicated server
const string DEDICATED_SERVER_IP = "127.0.0.1";
const int DEDICATED_SERVER_PORT = 7777;
public GameObject ErrorPanel;
public Text ErrorText;
public InputField ipAddressField;
public TMP_InputField playerNameField;
private int connectionTimeoutTime = 5;
void Start() {
// Make sure the Error Panel is not enabled to start
ErrorPanel.SetActive(false);
PlayerPrefs.GetString("PlayerName");
}
// Connect to the dedicated server
public void ConnectDedicatedServer () {
// Throw an error for now
ThrowError("Not implemented yet.");
}
// Host a private server
public void HostPrivateServer() {
// Set the players name
PlayerPrefs.SetString("PlayerName", playerNameField.text);
// Start a server and join (hosting)
GameNetPortal.Instance.StartHost();
}
// Connect to a private server via IP Address
public void ConnectToPrivateServer() {
string ipAddress = ipAddressField.text;
int port = 7777;
// Check if the IP Address is valid
if (!ValidateIPv4(ipAddress)) {
ThrowError("Invalid IP Address! Please enter a valid IP Address and try again!");
return;
}
// IP Address is valid - Attempt to connect
// Set the players name
PlayerPrefs.SetString("PlayerName", playerNameField.text);
// Start the game client
ClientGameNetPortal.Instance.StartClient(ipAddress, port);
// Run a coroutine to check if the client connects to the server
StartCoroutine(checkIsConnectedClient());
}
IEnumerator checkIsConnectedClient() {
yield return new WaitForSecondsRealtime(connectionTimeoutTime);
if (!NetworkManager.Singleton.IsConnectedClient) {
// Failed to connect to the server
NetworkManager.Singleton.StopClient();
ThrowError("Could not connect to server!\nReason: Connection Timed Out");
}
}
private void ThrowError(string errorMsg) {
ErrorText.text = errorMsg;
ErrorPanel.SetActive(true);
}
public void DismissError() {
ErrorText.text = "";
ErrorPanel.SetActive(false);
}
// Method by: Habib (Stack Overflow)
// https://stackoverflow.com/questions/11412956/what-is-the-best-way-of-validating-an-ip-address
private bool ValidateIPv4(string ipString) {
if (string.IsNullOrWhiteSpace(ipString)) {
return false;
}
string[] splitValues = ipString.Split('.');
if (splitValues.Length != 4) {
return false;
}
byte tempForParsing;
return splitValues.All(r => byte.TryParse(r, out tempForParsing));
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7ea00cd263782d4484caf5ad9694247
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: