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.

254 lines
8.7 KiB

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Networking;
  6. namespace Networking.Server
  7. {
  8. [CreateAssetMenu(menuName = "Major Project/Networking/ClientList", order = 150)]
  9. public class ClientList : ScriptableObject, IEnumerable<ClientData>
  10. {
  11. #if UNITY_EDITOR
  12. [SerializeField]
  13. [Multiline]
  14. private string DevNotes;
  15. #endif
  16. [SerializeField]
  17. private Inventory StartInventory;
  18. #region Public Variables
  19. /// <summary>
  20. /// All Clients which are Currently Connected;
  21. /// </summary>
  22. public List<ClientData> ConnectedClients;
  23. /// <summary>
  24. /// Clients which connected at one point but no longer are
  25. /// Usefull if a client needs to reconnect
  26. /// </summary>
  27. public List<ClientData> DisconnectedClients;
  28. private List<NetworkConnection> PotentialClients = new List<NetworkConnection>();
  29. /// <summary>
  30. /// Called when a client connects or disconnet
  31. /// </summary>
  32. public System.Action<List<ClientData>> OnClientsChange;
  33. #endregion Public Variables
  34. #region Private Variables
  35. public ServerObject server;
  36. #endregion Private Variables
  37. /// <summary>
  38. /// Clears the lists
  39. /// </summary>
  40. public void Reset()
  41. {
  42. ConnectedClients = new List<ClientData>();
  43. DisconnectedClients = new List<ClientData>();
  44. PotentialClients = new List<NetworkConnection>();
  45. }
  46. /// <summary>
  47. /// Resets the client list + registers handlers with the server
  48. /// </summary>
  49. /// <param name="serverObject">Server to register handlers with</param>
  50. public void SetUp(ServerObject serverObject)
  51. {
  52. this.server = serverObject;
  53. Reset();
  54. server.RegisterHandler(MsgType.Connect, OnClientConnect);
  55. server.RegisterHandler(MsgType.Disconnect, OnClientDisconnect);
  56. server.RegisterHandler(LoginProtocols.SendingLoginDetails, OnClientLogin);
  57. }
  58. public void OnClientConnect(NetworkMessage msg)
  59. {
  60. //Debug.Log("newClient: " + msg.conn.address + ", " + msg.conn.Hash() + ", " + msg.conn.hostId);
  61. if (ConnectedClients.Any(p => p.ID == msg.channelId))
  62. {
  63. Debug.LogError("Client[" + msg.channelId + "] already connected");
  64. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  65. return;
  66. }
  67. if (!PotentialClients.Contains(msg.conn))
  68. PotentialClients.Add(msg.conn);
  69. msg.conn.Send(LoginProtocols.RequestLoginDetails, new LoginProtocols.EmptyMsg());
  70. ConnectedClients.ForEach(p => msg.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(p.Name, p.Color, p.characterAnimal)));
  71. }
  72. public void OnClientDisconnect(NetworkMessage msg)
  73. {
  74. PotentialClients.RemoveAll(p => p == msg.conn);
  75. if (!ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
  76. {
  77. Debug.LogError("Unknown client disconnect [" + msg.conn.Hash() + "]");
  78. return;
  79. }
  80. ClientData client = ConnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
  81. client.Lives = 0;
  82. client.playerCharacter.lives = 0;
  83. ConnectedClients.Remove(client);
  84. DisconnectedClients.Add(client);
  85. ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
  86. PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
  87. Debug.Log("Disconnected: " + client.Name);
  88. //somewhere here we need to remove the disconnected client from the client list and update such things
  89. OnClientsChange?.Invoke(ConnectedClients);
  90. }
  91. public void OnClientLogin(NetworkMessage msg)
  92. {
  93. LoginProtocols.LoginMsg loginMsg;
  94. if (!msg.TryRead(out loginMsg))
  95. {
  96. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  97. return;
  98. }
  99. if (ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
  100. {
  101. Debug.LogError("Client[" + msg.channelId + "] already connected");
  102. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  103. return;
  104. }
  105. ClientData newClient = DisconnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
  106. if (newClient != default)
  107. {
  108. Debug.Log("Reconnection: " + loginMsg.Name + ((loginMsg.Name != newClient.Name) ? (" (Prev. " + newClient.Name +")") : ""));
  109. DisconnectedClients.Remove(newClient);
  110. }
  111. else
  112. {
  113. //Debug.Log("new Connection: " + loginMsg.Name);
  114. newClient = new ClientData();
  115. newClient.Inventory = Inventory.Clone(StartInventory);
  116. }
  117. newClient.Color = loginMsg.Color;
  118. newClient.characterAnimal = loginMsg.Animal;
  119. newClient.Name = loginMsg.Name;
  120. newClient.conn = msg.conn;
  121. ConnectedClients.Add(newClient);
  122. ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
  123. PotentialClients.RemoveAll(p => p == newClient.conn);
  124. PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
  125. newClient.conn.Send(LoginProtocols.LoginSuccess, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal));
  126. OnClientsChange.Invoke(ConnectedClients);
  127. newClient.SendInventory();
  128. newClient.SendLives();
  129. newClient.ChangeScene("LobbyWait");
  130. }
  131. #region IEnumerable Implementation
  132. public IEnumerator<ClientData> GetEnumerator()
  133. {
  134. return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
  135. }
  136. IEnumerator IEnumerable.GetEnumerator()
  137. {
  138. return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
  139. }
  140. #endregion IEnumerable Implementation
  141. /// <summary>
  142. /// Returns client with id
  143. /// </summary>
  144. /// <param name="id">id to find client with</param>
  145. /// <returns>client with provided id else null</returns>
  146. public ClientData this[int id] {
  147. get {
  148. return ConnectedClients.FirstOrDefault(p => p.ID == id);
  149. }
  150. }
  151. }
  152. [System.Serializable]
  153. public class ClientData
  154. {
  155. /// <summary>
  156. /// Client Name
  157. /// </summary>
  158. public string Name;
  159. /// <summary>
  160. /// Color which represents player, picked by player
  161. /// </summary>
  162. public Color Color;
  163. /// <summary>
  164. /// Clients Current Score
  165. /// </summary>
  166. public int Score;
  167. /// <summary>
  168. /// Clients Current Lives
  169. /// </summary>
  170. public int Lives = 3;
  171. /// <summary>
  172. /// Clients character animal - needed for instantiation
  173. /// </summary>
  174. public string characterAnimal = "Bear";
  175. /// <summary>
  176. /// Network connection ID
  177. /// </summary>
  178. public int ID { get { return (conn != null) ? conn.Hash() : -1; }}
  179. /// <summary>
  180. /// Connection to Client
  181. /// </summary>
  182. public NetworkConnection conn;
  183. /// <summary>
  184. /// Current Logic elements held by player
  185. /// </summary>
  186. public Inventory Inventory;
  187. public Character playerCharacter;
  188. public void SendInventory()
  189. {
  190. //Debug.Log("Sending inventory");
  191. conn.SendByChannel(LogicProtocols.SendInventory, new LogicProtocols.InventoryMsg(Inventory), TransportConfigure.ReliableFragmented);
  192. }
  193. public void SendLives()
  194. {
  195. conn.Send(LogicProtocols.SendLives, new LogicProtocols.FloatMsg(Lives));
  196. }
  197. public void ChangeScene(string scene, bool Additive = false)
  198. {
  199. conn.Send(LoginProtocols.SceneChange, new LoginProtocols.SceneMsg(scene,Additive));
  200. }
  201. }
  202. }