Skip to content

Instantly share code, notes, and snippets.

@arun02139
Created August 23, 2016 09:48
Show Gist options
  • Save arun02139/c1113703b3dbe98cb0be668870a27442 to your computer and use it in GitHub Desktop.
Save arun02139/c1113703b3dbe98cb0be668870a27442 to your computer and use it in GitHub Desktop.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.Networking;
using UnityEngine.Networking.Types;
using UnityEngine.Networking.Match;
using System.Collections;
namespace Prototype.NetworkLobby
{
public class LobbyManager : NetworkLobbyManager
{
static short MsgKicked = MsgType.Highest + 1;
static public LobbyManager s_Singleton;
[Header("Unity UI Lobby")]
[Tooltip("Time in second between all players ready & match start")]
public float prematchCountdown = 5.0f;
[Space]
[Header("UI Reference")]
public LobbyTopPanel topPanel;
public RectTransform mainMenuPanel;
public RectTransform lobbyPanel;
public LobbyInfoPanel infoPanel;
public LobbyCountdownPanel countdownPanel;
public GameObject addPlayerButton;
protected RectTransform currentPanel;
public Button backButton;
public Text statusInfo;
public Text hostInfo;
//Client numPlayers from NetworkManager is always 0, so we count (throught connect/destroy in LobbyPlayer) the number
//of players, so that even client know how many player there is.
[HideInInspector]
public int _playerNumber = 0;
//used to disconnect a client properly when exiting the matchmaker
[HideInInspector]
public bool _isMatchmaking = false;
protected bool _disconnectServer = false;
protected ulong _currentMatchID;
protected LobbyHook _lobbyHook;
void Start()
{
s_Singleton = this;
_lobbyHook = GetComponent<Prototype.NetworkLobby.LobbyHook>();
currentPanel = mainMenuPanel;
backButton.gameObject.SetActive(false);
// GetComponent<Canvas>().enabled = true;
DontDestroyOnLoad(gameObject);
SetServerInfo("Offline", "None");
}
public override void OnLobbyClientSceneChanged(NetworkConnection conn)
{
Debug.Log (string.Format ("LobbyManager.OnLobbyClientSceneChanged: SceneManager.GetSceneAt(0).name={0} (SceneManager.sceneCount={1})",
SceneManager.GetSceneAt(0).name, SceneManager.sceneCount));
if (SceneManager.GetSceneAt(0).name == lobbyScene)
{
if (topPanel.isInGame)
{
ChangeTo(lobbyPanel);
if (_isMatchmaking)
{
if (conn.playerControllers[0].unetView.isServer)
{
backDelegate = StopHostClbk;
}
else
{
backDelegate = StopClientClbk;
}
}
else
{
if (conn.playerControllers[0].unetView.isClient)
{
backDelegate = StopHostClbk;
}
else
{
backDelegate = StopClientClbk;
}
}
}
else
{
ChangeTo(mainMenuPanel);
}
topPanel.ToggleVisibility(true);
topPanel.isInGame = false;
}
else
{
ChangeTo(null);
Destroy(GameObject.Find("MainMenuUI(Clone)"));
//backDelegate = StopGameClbk;
topPanel.isInGame = true;
topPanel.ToggleVisibility(false);
}
}
public void ChangeTo(RectTransform newPanel)
{
if (currentPanel != null)
{
currentPanel.gameObject.SetActive(false);
}
if (newPanel != null)
{
newPanel.gameObject.SetActive(true);
}
currentPanel = newPanel;
if (currentPanel != mainMenuPanel)
{
backButton.gameObject.SetActive(true);
}
else
{
backButton.gameObject.SetActive(false);
SetServerInfo("Offline", "None");
_isMatchmaking = false;
}
}
public void DisplayIsConnecting()
{
var _this = this;
infoPanel.Display("Connecting...", "Cancel", () => { _this.backDelegate(); });
}
public void SetServerInfo(string status, string host)
{
statusInfo.text = status;
hostInfo.text = host;
}
public delegate void BackButtonDelegate();
public BackButtonDelegate backDelegate;
public void GoBackButton()
{
backDelegate();
}
// ----------------- Server management
public void AddLocalPlayer()
{
TryToAddPlayer();
}
public void RemovePlayer(LobbyPlayer player)
{
player.RemovePlayer();
}
public void SimpleBackClbk()
{
ChangeTo(mainMenuPanel);
}
public void StopHostClbk()
{
if (_isMatchmaking)
{
matchMaker.DestroyMatch((NetworkID)_currentMatchID, 0, OnDestroyMatch); // HARDCODE
_disconnectServer = true;
}
else
{
StopHost();
}
ChangeTo(mainMenuPanel);
}
public void StopClientClbk()
{
StopClient();
if (_isMatchmaking)
{
StopMatchMaker();
}
ChangeTo(mainMenuPanel);
}
public void StopServerClbk()
{
StopServer();
ChangeTo(mainMenuPanel);
}
class KickMsg : MessageBase { }
public void KickPlayer(NetworkConnection conn)
{
conn.Send(MsgKicked, new KickMsg());
}
public void KickedMessageHandler(NetworkMessage netMsg)
{
infoPanel.Display("Kicked by Server", "Close", null);
netMsg.conn.Disconnect();
}
//===================
public override void OnStartServer ()
{
base.OnStartServer (); // empty stub as of Unity 5.4 (gets called near start of function NetworkManager.StartServer)
}
public override void OnStartHost()
{
base.OnStartHost();
ChangeTo(lobbyPanel);
backDelegate = StopHostClbk;
SetServerInfo("Hosting", networkAddress);
}
public override void OnMatchCreate (bool success, string extendedInfo, MatchInfo matchInfo)
{
base.OnMatchCreate (success, extendedInfo, matchInfo);
_currentMatchID = (ulong)matchInfo.networkId;
}
public override void OnDestroyMatch (bool success, string extendedInfo)
{
base.OnDestroyMatch (success, extendedInfo);
if (_disconnectServer)
{
StopMatchMaker();
StopHost();
}
}
//allow to handle the (+) button to add/remove player
public void OnPlayersNumberModified(int count)
{
_playerNumber += count;
int localPlayerCount = 0;
foreach (PlayerController p in ClientScene.localPlayers)
localPlayerCount += (p == null || p.playerControllerId == -1) ? 0 : 1;
addPlayerButton.SetActive(localPlayerCount < maxPlayersPerConnection && _playerNumber < maxPlayers);
}
// ----------------- Server callbacks ------------------
//we want to disable the button JOIN if we don't have enough player
//But OnLobbyClientConnect isn't called on hosting player. So we override the lobbyPlayer creation
public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject obj = Instantiate(lobbyPlayerPrefab.gameObject) as GameObject;
LobbyPlayer newPlayer = obj.GetComponent<LobbyPlayer>();
newPlayer.ToggleJoinButton(numPlayers + 1 >= minPlayers);
for (int i = 0; i < lobbySlots.Length; ++i)
{
LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
if (p != null)
{
p.RpcUpdateRemoveButton();
p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
}
}
return obj;
}
public override void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
{
for (int i = 0; i < lobbySlots.Length; ++i)
{
LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
if (p != null)
{
p.RpcUpdateRemoveButton();
p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
}
}
}
public override void OnLobbyServerDisconnect(NetworkConnection conn)
{
for (int i = 0; i < lobbySlots.Length; ++i)
{
LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
if (p != null)
{
p.RpcUpdateRemoveButton();
p.ToggleJoinButton(numPlayers >= minPlayers);
}
}
}
// NOTE: called towards the end of the NetworkLobbyManager.SceneLoadedForPlayer function. From the Unity
// docs: "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." NOTE: if we return 'false', the lobby player will not be replaced
// with the game player (i.e. NetworkLobbyManager.SceneLoadedForPlayer will return early before
// NetworkServer.ReplacePlayerForConnection is called)
public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
{
// sanity-check (this should never be the case since it's a server-side callback)
if (!NetworkServer.active)
{
ClientDebugUI.i.Log (string.Format ("LobbyManager.OnLobbyServerSceneLoadedForPlayer: unexpected, returning false"), GameColors.Red);
return false;
}
// this hook allows you to apply state data from the lobby-player to the game-player
// just subclass "LobbyHook" and add it to the lobby object.
if (_lobbyHook)
{
ServerDebugUI.i.Log (string.Format ("LobbyManager.OnLobbyServerSceneLoadedForPlayer: lobby hook found for player {0}", lobbyPlayer.name));
// execute the lobby hook logic (presumably utilizing info from the lobby player to setup teh game player)
_lobbyHook.OnLobbyServerSceneLoadedForPlayer (this, lobbyPlayer, gamePlayer);
}
NetworkIdentity gamePlayerNetIdentity = gamePlayer.GetComponent<NetworkIdentity> ();
bool gamePlayerHasNetIdentity = gamePlayerNetIdentity != null;
string gamePlayerNetIdentityString = " gamePlayerNetIdentity: " + (gamePlayerHasNetIdentity ? gamePlayerNetIdentity.netId.ToString() : "(null)");
NetworkIdentity lobbyPlayerNetIdentity = lobbyPlayer.GetComponent<NetworkIdentity> ();
bool lobbyPlayerHasNetIdentity = lobbyPlayerNetIdentity != null;
string lobbyPlayerNetIdentityString = " lobbyPlayerNetIdentity: " + (lobbyPlayerHasNetIdentity ? lobbyPlayerNetIdentity.netId.ToString() : "(null)");
// create each player's units by spawning on the server
if (gamePlayerNetIdentity != null)
{
ServerDebugUI.i.Log (string.Format ("LobbyManager.OnLobbyServerSceneLoadedForPlayer: ready to spawn player units!", ""));
ServerDebugUI.i.Log (gamePlayerNetIdentityString);
ServerDebugUI.i.Log (lobbyPlayerNetIdentityString);
SpawnPlayerUnits (gamePlayerNetIdentity);
}
// ..this shouldn't happen (gamePlayer should be NetworkPlayer prefab, which has a NetworkIdentity)
else
{
ServerDebugUI.i.Log (string.Format ("LobbyManager.OnLobbyServerSceneLoadedForPlayer: no NetworkIdentity " +
"component found on gamePlayer {0}", gamePlayer.name), GameColors.Red);
}
return true;
}
// --- Countdown management
// AMM NOTE: only seems to be called on the host
public override void OnLobbyServerPlayersReady()
{
bool allready = true;
for(int i = 0; i < lobbySlots.Length; ++i)
{
if(lobbySlots[i] != null)
allready &= lobbySlots[i].readyToBegin;
}
Debug.Log(string.Format ("LobbyManager.OnLobbyServerPlayersReady: allready = {0} (NetworkServer.active = {1})", allready, NetworkServer.active));
if(allready)
StartCoroutine(ServerCountdownCoroutine());
}
public IEnumerator ServerCountdownCoroutine()
{
float remainingTime = prematchCountdown;
int floorTime = Mathf.FloorToInt(remainingTime);
while (remainingTime > 0)
{
yield return null;
remainingTime -= Time.deltaTime;
int newFloorTime = Mathf.FloorToInt(remainingTime);
if (newFloorTime != floorTime)
{//to avoid flooding the network of message, we only send a notice to client when the number of plain seconds change.
floorTime = newFloorTime;
for (int i = 0; i < lobbySlots.Length; ++i)
{
if (lobbySlots[i] != null)
{//there is maxPlayer slots, so some could be == null, need to test it before accessing!
(lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(floorTime);
}
}
}
}
for (int i = 0; i < lobbySlots.Length; ++i)
{
if (lobbySlots[i] != null)
{
(lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(0);
}
}
ServerChangeScene(playScene);
}
// ----------------- Client callbacks ------------------
public override void OnClientConnect(NetworkConnection conn)
{
base.OnClientConnect(conn);
infoPanel.gameObject.SetActive(false);
conn.RegisterHandler(MsgKicked, KickedMessageHandler);
if (!NetworkServer.active)
{//only to do on pure client (not self hosting client)
ChangeTo(lobbyPanel);
backDelegate = StopClientClbk;
SetServerInfo("Client", networkAddress);
}
}
public override void OnClientDisconnect(NetworkConnection conn)
{
Debug.Log (string.Format ("LobbyManager.OnClientDisconnect: conn = \n{0}", conn.PrettyPrint()));
base.OnClientDisconnect(conn);
ChangeTo(mainMenuPanel);
}
public override void OnClientError(NetworkConnection conn, int errorCode)
{
ChangeTo(mainMenuPanel);
infoPanel.Display("Cient error : " + (errorCode == 6 ? "timeout" : errorCode.ToString()), "Close", null);
}
// create a single 'soldier' unit (index 0)
void SpawnPlayerUnits(NetworkIdentity netIdentity)
{
// safety-check
if(this.spawnPrefabs.Count != 1)
{
ServerDebugUI.i.Log (string.Format("LobbyManager.SpawnPlayerUnits: spawnPrefabs.Count={0} (NetworkServer.active={1}), aborting",
spawnPrefabs.Count, NetworkServer.active), GameColors.Red);
}
GameObject soldierUnitPrefab = spawnPrefabs [0];
string prefabName = soldierUnitPrefab == null ? "(null)" : soldierUnitPrefab.name;
ServerDebugUI.i.Log (string.Format("LobbyManager.SpawnPlayerUnits: spawning {0} for gamePlayer ({1})",
prefabName, netIdentity.netId));
// instantiate (on the server)
var unit = (GameObject)Instantiate(soldierUnitPrefab);
// spawn on clients across the network
NetworkServer.Spawn (unit);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment