385 lines
10 KiB
C#
385 lines
10 KiB
C#
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<PlayerInfo> Players = new List<PlayerInfo>();
|
|
|
|
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<GameInfoMsg> Games = new List<GameInfoMsg>();
|
|
|
|
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<LobbyPlayerMsg> Players = new List<LobbyPlayerMsg>();
|
|
|
|
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(),
|
|
};
|
|
}
|
|
}
|
|
}
|