using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading; using Hazel; using Hazel.Udp; using UnityEngine; namespace InnerNet { public class InnerNetServer : DestroyableSingleton { // 单局最大玩家数 public const int MaxPlayers = 10; public bool Running; // 是本地游戏的话id是这个32 public const int LocalGameId = 32; private const int InvalidHost = -1; private int HostId = -1; public HashSet ipBans = new HashSet(); public int Port = 22023; /* public enum GameStates : byte { NotStarted, Started, Ended, Destroyed } */ [SerializeField] private GameStates GameState; private NetworkConnectionListener listener; private List Clients = new List(); // 某个玩家的连接 protected class Player { private static int IdCount = 1; public int Id; public Connection Connection; public LimboStates LimboState; public Player(Connection connection) { this.Id = Interlocked.Increment(ref InnerNetServer.Player.IdCount); this.Connection = connection; } } // 销毁这个单例 public override void OnDestroy() { this.StopServer(); base.OnDestroy(); } // 开启本地服务器,监听端口 // 在HostGameButton.CoStartGame中调用 public void StartAsServer() { if (this.listener != null) { this.StopServer(); } this.GameState = GameStates.NotStarted; this.listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, this.Port), IPMode.IPv4, null); this.listener.NewConnection += this.OnServerConnect; this.listener.Start(); this.Running = true; } // 停止服务器 public void StopServer() { this.HostId = -1; this.Running = false; this.GameState = GameStates.Destroyed; if (this.listener != null) { this.listener.Close(); this.listener.Dispose(); this.listener = null; } List clients = this.Clients; lock (clients) { this.Clients.Clear(); } } public static bool IsCompatibleVersion(int version) { return Constants.CompatVersions.Contains(version); } // 收到某个玩家的连接 private void OnServerConnect(NewConnectionEventArgs evt) { MessageReader handshakeData = evt.HandshakeData; try { if (evt.HandshakeData.Length < 5) { InnerNetServer.SendIncorrectVersion(evt.Connection); return; } if (!InnerNetServer.IsCompatibleVersion(handshakeData.ReadInt32())) { InnerNetServer.SendIncorrectVersion(evt.Connection); return; } } finally { handshakeData.Recycle(); } InnerNetServer.Player client = new InnerNetServer.Player(evt.Connection); Debug.Log(string.Format("Client {0} added: {1}", client.Id, evt.Connection.EndPoint)); UdpConnection udpConnection = (UdpConnection)evt.Connection; udpConnection.KeepAliveInterval = 1500; udpConnection.DisconnectTimeout = 6000; udpConnection.ResendPingMultiplier = 1.5f; udpConnection.DataReceived += delegate(DataReceivedEventArgs e) { this.OnDataReceived(client, e); }; udpConnection.Disconnected += delegate(object o, DisconnectedEventArgs e) { this.ClientDisconnect(client); }; } private static void SendIncorrectVersion(Connection connection) { MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.StartMessage(1); messageWriter.Write(5); messageWriter.EndMessage(); connection.Send(messageWriter); messageWriter.Recycle(); } private void Connection_DataSentRaw(byte[] data, int length) { Debug.Log("Server Sent: " + string.Join(" ", (from b in data select b.ToString()).ToArray(), 0, length)); } private void OnDataReceived(InnerNetServer.Player client, DataReceivedEventArgs evt) { MessageReader message = evt.Message; if (message.Length <= 0) { Debug.Log("Server got 0 bytes"); message.Recycle(); return; } try { while (message.Position < message.Length) { this.HandleMessage(client, message.ReadMessage(), evt.SendOption); } } catch (Exception arg) { Debug.Log(string.Format("{0}\r\n{1}", string.Join(" ", message.Buffer), arg)); } finally { message.Recycle(); } } /* public static class Tags { public const byte HostGame = 0; public const byte JoinGame = 1; public const byte StartGame = 2; public const byte RemoveGame = 3; public const byte RemovePlayer = 4; public const byte GameData = 5; public const byte GameDataTo = 6; public const byte JoinedGame = 7; public const byte EndGame = 8; public const byte GetGameList = 9; public const byte AlterGame = 10; public const byte KickPlayer = 11; public const byte WaitForHost = 12; public const byte Redirect = 13; } */ // 处理收到的消息,在网络线程执行 // reader是数据 private void HandleMessage(InnerNetServer.Player client, MessageReader reader, SendOption sendOption) { switch (reader.Tag) { case 0: // HostGame { Debug.Log("Server got host game"); MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.StartMessage(0); // tag messageWriter.Write(LocalGameId); // gameId messageWriter.EndMessage(); client.Connection.Send(messageWriter); messageWriter.Recycle(); return; } case 1: // JoinGame { Debug.Log("Server got join game"); if (reader.ReadInt32() == LocalGameId) { this.JoinGame(client); return; } MessageWriter messageWriter2 = MessageWriter.Get(SendOption.Reliable); messageWriter2.StartMessage(1); // tag messageWriter2.Write(3); // messageWriter2.EndMessage(); client.Connection.Send(messageWriter2); messageWriter2.Recycle(); return; } case 2: // StartGame if (reader.ReadInt32() == 32) { this.StartGame(reader, client); return; } break; case 3: // RemoveGame if (reader.ReadInt32() == 32) { this.ClientDisconnect(client); return; } break; case 4: // remove player case 7: // joined game case 9: // get game list case 10: // alter game break; case 5: // Tags.GameData if (this.Clients.Contains(client)) { if (reader.ReadInt32() == 32) { MessageWriter messageWriter3 = MessageWriter.Get(sendOption); messageWriter3.CopyFrom(reader); // 广播这个消息 this.Broadcast(messageWriter3, client); messageWriter3.Recycle(); return; } } else if (this.GameState == GameStates.Started) // 没有这个连接就踢掉这个错误的连接 { client.Connection.Dispose(); return; } break; case 6: // GameDataTo 到指定玩家,和Tags.GameData不同,包括Rpc if (this.Clients.Contains(client)) { if (reader.ReadInt32() == 32) { int targetId = reader.ReadPackedInt32(); MessageWriter messageWriter4 = MessageWriter.Get(sendOption); messageWriter4.CopyFrom(reader); this.SendTo(messageWriter4, targetId); messageWriter4.Recycle(); return; } } else if (this.GameState == GameStates.Started) { Debug.Log("GameDataTo: Server didn't have client"); client.Connection.Dispose(); return; } break; case 8: // EndGame if (reader.ReadInt32() == 32) { this.EndGame(reader, client); return; } break; case 11: // kick player if (reader.ReadInt32() == 32) { this.KickPlayer(reader.ReadPackedInt32(), reader.ReadBoolean()); } break; default: return; } } // 踢玩家 private void KickPlayer(int targetId, bool ban) { List clients = this.Clients; lock (clients) { InnerNetServer.Player player = null; // 找到对应的玩家的连接 for (int i = 0; i < this.Clients.Count; i++) { if (this.Clients[i].Id == targetId) { player = this.Clients[i]; break; } } if (player != null) { if (ban) // 是否ban掉这个ip { HashSet obj = this.ipBans; lock (obj) { IPEndPoint endPoint = player.Connection.EndPoint; this.ipBans.Add(endPoint.Address.ToString()); } } MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.StartMessage(11); messageWriter.Write(32); messageWriter.WritePacked(targetId); messageWriter.Write(ban); messageWriter.EndMessage(); this.Broadcast(messageWriter, null); messageWriter.Recycle(); } } } protected void JoinGame(InnerNetServer.Player client) { HashSet obj = this.ipBans; lock (obj) { IPEndPoint endPoint = client.Connection.EndPoint; // 如果这个ip被ban掉了,踢掉这个玩家 if (this.ipBans.Contains(endPoint.Address.ToString())) { MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.StartMessage(1); messageWriter.Write(6); messageWriter.EndMessage(); client.Connection.Send(messageWriter); messageWriter.Recycle(); return; } } List clients = this.Clients; lock (clients) { switch (this.GameState) { case GameStates.NotStarted: this.HandleNewGameJoin(client); break; default: { MessageWriter messageWriter2 = MessageWriter.Get(SendOption.Reliable); messageWriter2.StartMessage(1); messageWriter2.Write(2); messageWriter2.EndMessage(); client.Connection.Send(messageWriter2); messageWriter2.Recycle(); break; } case GameStates.Ended: this.HandleRejoin(client); break; } } } private void HandleRejoin(InnerNetServer.Player client) { if (client.Id == this.HostId) { this.GameState = GameStates.NotStarted; this.HandleNewGameJoin(client); MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); for (int i = 0; i < this.Clients.Count; i++) { InnerNetServer.Player player = this.Clients[i]; if (player != client) { try { this.WriteJoinedMessage(player, messageWriter, true); player.Connection.Send(messageWriter); } catch { } } } messageWriter.Recycle(); return; } if (this.Clients.Count >= 9) { MessageWriter messageWriter2 = MessageWriter.Get(SendOption.Reliable); messageWriter2.StartMessage(1); messageWriter2.Write(1); messageWriter2.EndMessage(); client.Connection.Send(messageWriter2); messageWriter2.Recycle(); return; } this.Clients.Add(client); client.LimboState = LimboStates.WaitingForHost; MessageWriter messageWriter3 = MessageWriter.Get(SendOption.Reliable); try { messageWriter3.StartMessage(12); messageWriter3.Write(32); messageWriter3.Write(client.Id); messageWriter3.EndMessage(); client.Connection.Send(messageWriter3); this.BroadcastJoinMessage(client, messageWriter3); } catch { } finally { messageWriter3.Recycle(); } } private void HandleNewGameJoin(InnerNetServer.Player client) { if (this.Clients.Count >= 10) { MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); try { messageWriter.StartMessage(1); messageWriter.Write(1); messageWriter.EndMessage(); client.Connection.Send(messageWriter); } catch { } finally { messageWriter.Recycle(); } return; } this.Clients.Add(client); client.LimboState = LimboStates.PreSpawn; if (this.HostId == -1) { this.HostId = this.Clients[0].Id; } if (this.HostId == client.Id) { client.LimboState = LimboStates.NotLimbo; } MessageWriter messageWriter2 = MessageWriter.Get(SendOption.Reliable); try { this.WriteJoinedMessage(client, messageWriter2, true); client.Connection.Send(messageWriter2); this.BroadcastJoinMessage(client, messageWriter2); } catch { } finally { messageWriter2.Recycle(); } } // 游戏结束 private void EndGame(MessageReader message, InnerNetServer.Player source) { if (source.Id == this.HostId) { this.GameState = GameStates.Ended; MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.CopyFrom(message); this.Broadcast(messageWriter, null); messageWriter.Recycle(); List clients = this.Clients; lock (clients) { this.Clients.Clear(); return; } } Debug.LogWarning("Reset request rejected from: " + source.Id); } // 开始游戏,房主点击了开始按钮后,服务器向其他玩家广播开始消息 private void StartGame(MessageReader message, InnerNetServer.Player source) { this.GameState = GameStates.Started; MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.CopyFrom(message); this.Broadcast(messageWriter, null); messageWriter.Recycle(); } private void ClientDisconnect(InnerNetServer.Player client) { Debug.Log("Server DC client " + client.Id); List clients = this.Clients; lock (clients) { this.Clients.Remove(client); client.Connection.Dispose(); if (this.Clients.Count > 0) { this.HostId = this.Clients[0].Id; } } MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable); messageWriter.StartMessage(4); messageWriter.Write(32); messageWriter.Write(client.Id); messageWriter.Write(this.HostId); messageWriter.Write(0); messageWriter.EndMessage(); this.Broadcast(messageWriter, null); messageWriter.Recycle(); } // 精确发给某个玩家,而不是广播 protected void SendTo(MessageWriter msg, int targetId) { List clients = this.Clients; lock (clients) { for (int i = 0; i < this.Clients.Count; i++) { InnerNetServer.Player player = this.Clients[i]; if (player.Id == targetId) { try { player.Connection.Send(msg); break; } catch (Exception exception) { Debug.LogException(exception); break; } } } } } // 广播消息 protected void Broadcast(MessageWriter msg, InnerNetServer.Player source) { List clients = this.Clients; lock (clients) { // 遍历所有的玩家,广播数据 for (int i = 0; i < this.Clients.Count; i++) { InnerNetServer.Player player = this.Clients[i]; if (player != source) { try { // 发送数据 player.Connection.Send(msg); } catch { } } } } } private void BroadcastJoinMessage(InnerNetServer.Player client, MessageWriter msg) { msg.Clear(SendOption.Reliable); msg.StartMessage(1); msg.Write(32); msg.Write(client.Id); msg.Write(this.HostId); msg.EndMessage(); this.Broadcast(msg, client); } private void WriteJoinedMessage(InnerNetServer.Player client, MessageWriter msg, bool clear) { if (clear) { msg.Clear(SendOption.Reliable); } msg.StartMessage(7); msg.Write(32); msg.Write(client.Id); msg.Write(this.HostId); msg.WritePacked(this.Clients.Count - 1); for (int i = 0; i < this.Clients.Count; i++) { InnerNetServer.Player player = this.Clients[i]; if (player != client) { msg.WritePacked(player.Id); } } msg.EndMessage(); } } }