You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

258 lines
8.7 KiB

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace Networking.Server
{
[CreateAssetMenu(menuName = "Major Project/Networking/ClientList", order = 150)]
public class ClientList : ScriptableObject, IEnumerable<ClientData>
{
#if UNITY_EDITOR
[SerializeField]
[Multiline]
private string DevNotes;
#endif
[SerializeField]
private Inventory StartInventory;
#region Public Variables
/// <summary>
/// All Clients which are Currently Connected;
/// </summary>
public List<ClientData> ConnectedClients;
/// <summary>
/// Clients which connected at one point but no longer are
/// Usefull if a client needs to reconnect
/// </summary>
public List<ClientData> DisconnectedClients;
private List<NetworkConnection> PotentialClients = new List<NetworkConnection>();
/// <summary>
/// Called when a client connects or disconnet
/// </summary>
public System.Action<List<ClientData>> OnClientsChange;
#endregion Public Variables
#region Private Variables
public ServerObject server;
#endregion Private Variables
/// <summary>
/// Clears the lists
/// </summary>
public void Reset()
{
ConnectedClients = new List<ClientData>();
DisconnectedClients = new List<ClientData>();
PotentialClients = new List<NetworkConnection>();
}
/// <summary>
/// Resets the client list + registers handlers with the server
/// </summary>
/// <param name="serverObject">Server to register handlers with</param>
public void SetUp(ServerObject serverObject)
{
this.server = serverObject;
Reset();
server.RegisterHandler(MsgType.Connect, OnClientConnect);
server.RegisterHandler(MsgType.Disconnect, OnClientDisconnect);
server.RegisterHandler(LoginProtocols.SendingLoginDetails, OnClientLogin);
}
public void OnClientConnect(NetworkMessage msg)
{
//Debug.Log("newClient: " + msg.conn.address + ", " + msg.conn.Hash() + ", " + msg.conn.hostId);
if (ConnectedClients.Any(p => p.ID == msg.channelId))
{
Debug.LogError("Client[" + msg.channelId + "] already connected");
msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
return;
}
if (!PotentialClients.Contains(msg.conn))
PotentialClients.Add(msg.conn);
msg.conn.Send(LoginProtocols.RequestLoginDetails, new LoginProtocols.EmptyMsg());
ConnectedClients.ForEach(p => msg.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(p.Name, p.Color, p.characterAnimal)));
}
public void OnClientDisconnect(NetworkMessage msg)
{
PotentialClients.RemoveAll(p => p == msg.conn);
if (!ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
{
Debug.LogError("Unknown client disconnect [" + msg.conn.Hash() + "]");
return;
}
ClientData client = ConnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
client.Lives = 0;
if (client.playerCharacter != null)
{
client.playerCharacter.lives = 0;
}
ConnectedClients.Remove(client);
DisconnectedClients.Add(client);
ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
Debug.Log("Disconnected: " + client.Name);
//somewhere here we need to remove the disconnected client from the client list and update such things
OnClientsChange?.Invoke(ConnectedClients);
}
public void OnClientLogin(NetworkMessage msg)
{
LoginProtocols.LoginMsg loginMsg;
if (!msg.TryRead(out loginMsg))
{
msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
return;
}
if (ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
{
Debug.LogError("Client[" + msg.channelId + "] already connected");
msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
return;
}
ClientData newClient = DisconnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
if (newClient != default)
{
Debug.Log("Reconnection: " + loginMsg.Name + ((loginMsg.Name != newClient.Name) ? (" (Prev. " + newClient.Name +")") : ""));
DisconnectedClients.Remove(newClient);
}
else
{
//Debug.Log("new Connection: " + loginMsg.Name);
newClient = new ClientData();
newClient.Inventory = Inventory.Clone(StartInventory);
}
newClient.Color = loginMsg.Color;
newClient.characterAnimal = loginMsg.Animal;
newClient.Name = loginMsg.Name;
newClient.conn = msg.conn;
ConnectedClients.Add(newClient);
ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
PotentialClients.RemoveAll(p => p == newClient.conn);
PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
newClient.conn.Send(LoginProtocols.LoginSuccess, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal));
OnClientsChange.Invoke(ConnectedClients);
newClient.SendInventory();
newClient.SendLives();
newClient.ChangeScene("LobbyWait");
}
#region IEnumerable Implementation
public IEnumerator<ClientData> GetEnumerator()
{
return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
}
#endregion IEnumerable Implementation
/// <summary>
/// Returns client with id
/// </summary>
/// <param name="id">id to find client with</param>
/// <returns>client with provided id else null</returns>
public ClientData this[int id] {
get {
return ConnectedClients.FirstOrDefault(p => p.ID == id);
}
}
}
[System.Serializable]
public class ClientData
{
/// <summary>
/// Client Name
/// </summary>
public string Name;
/// <summary>
/// Color which represents player, picked by player
/// </summary>
public Color Color;
/// <summary>
/// Clients Current Score
/// </summary>
public int Score;
/// <summary>
/// Clients Current Lives
/// </summary>
public int Lives = 3;
/// <summary>
/// Clients character animal - needed for instantiation
/// </summary>
public string characterAnimal = "Bear";
/// <summary>
/// Network connection ID
/// </summary>
public int ID { get { return (conn != null) ? conn.Hash() : -1; }}
/// <summary>
/// Connection to Client
/// </summary>
public NetworkConnection conn;
/// <summary>
/// Current Logic elements held by player
/// </summary>
public Inventory Inventory;
public Character playerCharacter;
public void SendInventory()
{
//Debug.Log("Sending inventory");
conn.SendByChannel(LogicProtocols.SendInventory, new LogicProtocols.InventoryMsg(Inventory), TransportConfigure.ReliableFragmented);
}
public void SendLives()
{
conn.Send(LogicProtocols.SendLives, new LogicProtocols.FloatMsg(Lives));
}
public void ChangeScene(string scene, bool Additive = false)
{
conn.Send(LoginProtocols.SceneChange, new LoginProtocols.SceneMsg(scene,Additive));
}
}
}