169 lines
5.2 KiB
C#
169 lines
5.2 KiB
C#
using BoneSync.Networking.Messages;
|
|
using Facepunch.Steamworks;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
#if TEST
|
|
using Xunit;
|
|
#endif
|
|
|
|
namespace BoneSync.Networking
|
|
{
|
|
|
|
public enum PacketReliability
|
|
{
|
|
Unreliable = 0,
|
|
Reliable = 1,
|
|
ReliableFast = 2,
|
|
}
|
|
public struct PacketInfo
|
|
{
|
|
public ulong id;
|
|
public ulong senderId;
|
|
public ulong receiverId;
|
|
public PacketType packetType;
|
|
public PacketReliability reliability;
|
|
|
|
public PacketInfo(
|
|
ulong senderId,
|
|
ulong receiverId,
|
|
PacketType packetType,
|
|
PacketReliability reliability = PacketReliability.Reliable,
|
|
ulong id = 0
|
|
)
|
|
{
|
|
this.senderId = senderId;
|
|
this.receiverId = receiverId;
|
|
this.packetType = packetType;
|
|
this.reliability = reliability;
|
|
this.id = id == 0 ? Packet.GenerateId() : id;
|
|
|
|
}
|
|
}
|
|
public class Packet
|
|
{
|
|
private static ulong _packetId = 1;
|
|
|
|
private static Dictionary<ulong, Dictionary<PacketType, ulong>> _latestPacketIds = new Dictionary<ulong, Dictionary<PacketType, ulong>>();
|
|
|
|
private static void SetLatestPacketId(ulong id, PacketType packetType, ulong value)
|
|
{
|
|
if (!_latestPacketIds.ContainsKey(id))
|
|
{
|
|
_latestPacketIds.Add(id, new Dictionary<PacketType, ulong>());
|
|
}
|
|
_latestPacketIds[id][packetType] = value;
|
|
}
|
|
|
|
private static ulong GetLatestPacketId(ulong id, PacketType packetType)
|
|
{
|
|
if (!_latestPacketIds.ContainsKey(id))
|
|
{
|
|
return 0;
|
|
}
|
|
if (!_latestPacketIds[id].ContainsKey(packetType))
|
|
{
|
|
return 0;
|
|
}
|
|
return _latestPacketIds[id][packetType];
|
|
}
|
|
|
|
public PacketInfo Info
|
|
{
|
|
get => _packetInfo;
|
|
private set => _packetInfo = value;
|
|
}
|
|
|
|
private PacketInfo _packetInfo;
|
|
private byte[] _dataBytes;
|
|
|
|
public Packet(PacketInfo packetInfo, byte[] data)
|
|
{
|
|
_packetInfo = packetInfo;
|
|
_dataBytes = data;
|
|
}
|
|
|
|
public static Packet FromBytes(byte[] bytes)
|
|
{
|
|
ByteEncoder byteEncoder = new ByteEncoder();
|
|
byteEncoder.WriteBytes(bytes);
|
|
|
|
byte packetType = byteEncoder.ReadByte();
|
|
byte reliability = byteEncoder.ReadByte();
|
|
ulong id = byteEncoder.ReadUlong();
|
|
ulong senderId = byteEncoder.ReadUlong();
|
|
ulong receiverId = byteEncoder.ReadUlong();
|
|
|
|
PacketInfo packetInfo = new PacketInfo(senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability, id);
|
|
return new Packet(packetInfo, byteEncoder.ToArray());
|
|
}
|
|
|
|
public byte[] ToBytes()
|
|
{
|
|
ByteEncoder byteEncoder = new ByteEncoder();
|
|
byteEncoder.WriteByte((byte)_packetInfo.packetType);
|
|
byteEncoder.WriteByte((byte)_packetInfo.reliability);
|
|
byteEncoder.WriteULong(_packetInfo.id);
|
|
byteEncoder.WriteULong(_packetInfo.senderId);
|
|
byteEncoder.WriteULong(_packetInfo.receiverId);
|
|
byteEncoder.WriteBytes(_dataBytes);
|
|
return byteEncoder.ToArray();
|
|
}
|
|
|
|
public static bool OnPacketReceived(Packet packet)
|
|
{
|
|
if (packet._packetInfo.reliability == PacketReliability.ReliableFast)
|
|
{
|
|
if (packet.Info.id <= GetLatestPacketId(packet.Info.senderId, packet.Info.packetType))
|
|
{
|
|
return false;
|
|
}
|
|
SetLatestPacketId(packet.Info.senderId, packet.Info.packetType, packet.Info.id);
|
|
}
|
|
|
|
NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet);
|
|
networkMessage.Execute();
|
|
return true;
|
|
}
|
|
|
|
public byte[] Data => _dataBytes;
|
|
|
|
public static ulong GenerateId()
|
|
{
|
|
return _packetId++;
|
|
}
|
|
}
|
|
#if TEST
|
|
public class PacketTests
|
|
{
|
|
[Fact]
|
|
public void TestPacketParsing()
|
|
{
|
|
Random random = new Random();
|
|
|
|
byte[] randomDataBytes = new byte[1024];
|
|
random.NextBytes(randomDataBytes);
|
|
PacketInfo originalPacketInfo = new PacketInfo(Packet.GenerateId(), 1, 2, PacketType.LobbyInfo);
|
|
Packet originalPacket = new Packet(originalPacketInfo, randomDataBytes);
|
|
|
|
byte[] bytes = originalPacket.ToBytes();
|
|
|
|
Packet parsedPacket = Packet.FromBytes(bytes);
|
|
|
|
Assert.Equal(originalPacket.Info.id, parsedPacket.Info.id);
|
|
Assert.Equal(originalPacket.Info.senderId, parsedPacket.Info.senderId);
|
|
Assert.Equal(originalPacket.Info.receiverId, parsedPacket.Info.receiverId);
|
|
Assert.Equal(originalPacket.Info.packetType, parsedPacket.Info.packetType);
|
|
|
|
Assert.Equal(originalPacket.Data, parsedPacket.Data);
|
|
|
|
|
|
Assert.Equal(randomDataBytes, parsedPacket.Data);
|
|
Assert.NotEqual(bytes, randomDataBytes);
|
|
}
|
|
}
|
|
#endif
|
|
}
|