using System.Collections.Generic; using XWorld.Framework; namespace XWorld.Framework.Protocol { // 框架通道(Channel.Framework)的 opcode;数值是线网契约,禁止随意改动 public enum FrameworkOpcode : ushort { Heartbeat = 1, MatchRequest = 2, MatchFound = 3, GameInput = 4, Snapshot = 5, RoomEnd = 6, Error = 7, GameListRequest = 8, GameListResponse = 9, RandomMatchRequest = 10, MatchAssigned = 11, LobbyJoin = 12, LobbyState = 13, LobbyMove = 14, LobbyLeave = 15, } public sealed class HeartbeatMsg { public long ClientTimeMs; public byte[] Encode() { var w = new PacketWriter(); w.WriteVarLong(ClientTimeMs); return w.ToArray(); } public static HeartbeatMsg Decode(byte[] data) { var r = new PacketReader(data); return new HeartbeatMsg { ClientTimeMs = r.ReadVarLong() }; } } public sealed class MatchRequestMsg { public string GameId; // null 编码为空字符串 public int Version; public byte[] Encode() { var w = new PacketWriter(); w.WriteString(GameId); w.WriteVarInt(Version); return w.ToArray(); } public static MatchRequestMsg Decode(byte[] data) { var r = new PacketReader(data); return new MatchRequestMsg { GameId = r.ReadString(), Version = r.ReadVarInt() }; } } public sealed class MatchFoundMsg { public string RoomId; // null 编码为空字符串 public int Version; public int SelfPlayerId; public List Players = new List(); public byte[] Encode() { var w = new PacketWriter(); w.WriteString(RoomId); w.WriteVarInt(Version); w.WriteVarInt(SelfPlayerId); w.WriteVarUInt((uint)Players.Count); foreach (var p in Players) { w.WriteVarInt(p.PlayerId); w.WriteString(p.Name); w.WriteBool(p.IsAI); } return w.ToArray(); } public static MatchFoundMsg Decode(byte[] data) { var r = new PacketReader(data); var m = new MatchFoundMsg { RoomId = r.ReadString(), Version = r.ReadVarInt(), SelfPlayerId = r.ReadVarInt(), }; uint n = r.ReadVarUInt(); for (uint i = 0; i < n; i++) { m.Players.Add(new PlayerInfo { PlayerId = r.ReadVarInt(), Name = r.ReadString(), IsAI = r.ReadBool(), }); } return m; } } public sealed class GameInfoMsg { public string GameId; public int Version; public string DisplayName; public int MinPlayers; public int MaxPlayers; } public sealed class GameListResponseMsg { public List Games = new List(); public byte[] Encode() { var w = new PacketWriter(); w.WriteVarUInt((uint)Games.Count); foreach (var g in Games) { w.WriteString(g.GameId); w.WriteVarInt(g.Version); w.WriteString(g.DisplayName); w.WriteVarInt(g.MinPlayers); w.WriteVarInt(g.MaxPlayers); } return w.ToArray(); } public static GameListResponseMsg Decode(byte[] data) { var r = new PacketReader(data); var msg = new GameListResponseMsg(); uint n = r.ReadVarUInt(); for (uint i = 0; i < n; i++) { msg.Games.Add(new GameInfoMsg { GameId = r.ReadString(), Version = r.ReadVarInt(), DisplayName = r.ReadString(), MinPlayers = r.ReadVarInt(), MaxPlayers = r.ReadVarInt(), }); } return msg; } } public sealed class MatchAssignedMsg { public string GameId; public int Version; public byte[] Encode() { var w = new PacketWriter(); w.WriteString(GameId); w.WriteVarInt(Version); return w.ToArray(); } public static MatchAssignedMsg Decode(byte[] data) { var r = new PacketReader(data); return new MatchAssignedMsg { GameId = r.ReadString(), Version = r.ReadVarInt() }; } } // 把一条小游戏业务输入封进框架通道(也可直接走 Channel.Game,二者择一,详见服务端子项目) public sealed class GameInputMsg { public ushort GameOpcode; public byte[] Payload; // null 与空数组线网等价,Decode 恒返回非 null public byte[] Encode() { var w = new PacketWriter(); w.WriteUInt16(GameOpcode); w.WriteBytes(Payload); return w.ToArray(); } public static GameInputMsg Decode(byte[] data) { var r = new PacketReader(data); return new GameInputMsg { GameOpcode = r.ReadUInt16(), Payload = r.ReadBytes() }; } } public sealed class SnapshotMsg { public int Tick; public byte[] StateBlob; // 由小游戏 Core.Encode(state) 产出,框架不解释内容;同上:null 与空等价 public byte[] Encode() { var w = new PacketWriter(); w.WriteVarInt(Tick); w.WriteBytes(StateBlob); return w.ToArray(); } public static SnapshotMsg Decode(byte[] data) { var r = new PacketReader(data); return new SnapshotMsg { Tick = r.ReadVarInt(), StateBlob = r.ReadBytes() }; } } public sealed class RoomEndMsg { public int WinnerPlayerId; // 0 表示平局/无胜者 public byte[] ResultBlob; // 小游戏自定义结算数据;同上:null 与空等价 public byte[] Encode() { var w = new PacketWriter(); w.WriteVarInt(WinnerPlayerId); w.WriteBytes(ResultBlob); return w.ToArray(); } public static RoomEndMsg Decode(byte[] data) { var r = new PacketReader(data); return new RoomEndMsg { WinnerPlayerId = r.ReadVarInt(), ResultBlob = r.ReadBytes() }; } } public sealed class ErrorMsg { public int Code; public string Message; // null 编码为空字符串 public byte[] Encode() { var w = new PacketWriter(); w.WriteVarInt(Code); w.WriteString(Message); return w.ToArray(); } public static ErrorMsg Decode(byte[] data) { var r = new PacketReader(data); return new ErrorMsg { Code = r.ReadVarInt(), Message = r.ReadString() }; } } public sealed class LobbyJoinMsg { public string Name; public int Figure; public byte[] Encode() { var w = new PacketWriter(); w.WriteString(Name); w.WriteVarInt(Figure); return w.ToArray(); } public static LobbyJoinMsg Decode(byte[] data) { var r = new PacketReader(data); return new LobbyJoinMsg { Name = r.ReadString(), Figure = r.ReadVarInt() }; } } public sealed class LobbyPlayerMsg { public int PlayerId; public string Name; public int Figure; public float X; public float Y; public float Z; public float DirX; public float DirZ; public bool Moving; public void Encode(PacketWriter w) { w.WriteVarInt(PlayerId); w.WriteString(Name); w.WriteVarInt(Figure); w.WriteSingle(X); w.WriteSingle(Y); w.WriteSingle(Z); w.WriteSingle(DirX); w.WriteSingle(DirZ); w.WriteBool(Moving); } public static LobbyPlayerMsg Decode(PacketReader r) { return new LobbyPlayerMsg { PlayerId = r.ReadVarInt(), Name = r.ReadString(), Figure = r.ReadVarInt(), X = r.ReadSingle(), Y = r.ReadSingle(), Z = r.ReadSingle(), DirX = r.ReadSingle(), DirZ = r.ReadSingle(), Moving = r.ReadBool(), }; } } public sealed class LobbyStateMsg { public List Players = new List(); public byte[] Encode() { var w = new PacketWriter(); w.WriteVarUInt((uint)Players.Count); foreach (var p in Players) p.Encode(w); return w.ToArray(); } public static LobbyStateMsg Decode(byte[] data) { var r = new PacketReader(data); var m = new LobbyStateMsg(); uint n = r.ReadVarUInt(); for (uint i = 0; i < n; i++) { m.Players.Add(LobbyPlayerMsg.Decode(r)); } return m; } } public sealed class LobbyMoveMsg { public int PlayerId; public float X; public float Y; public float Z; public float DirX; public float DirZ; public bool Moving; public byte[] Encode() { var w = new PacketWriter(); w.WriteVarInt(PlayerId); w.WriteSingle(X); w.WriteSingle(Y); w.WriteSingle(Z); w.WriteSingle(DirX); w.WriteSingle(DirZ); w.WriteBool(Moving); return w.ToArray(); } public static LobbyMoveMsg Decode(byte[] data) { var r = new PacketReader(data); return new LobbyMoveMsg { PlayerId = r.ReadVarInt(), X = r.ReadSingle(), Y = r.ReadSingle(), Z = r.ReadSingle(), DirX = r.ReadSingle(), DirZ = r.ReadSingle(), Moving = r.ReadBool(), }; } } }