Files
BoneSync/BoneSync/Networking/Packet.cs
2025-03-01 23:05:46 +02:00

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
}