Files
BoneSync/BoneSync/Networking/Messages/NetworkMessage.cs
2025-02-25 12:56:38 +02:00

117 lines
3.8 KiB
C#

using BoneSync.Networking.Transport;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace BoneSync.Networking.Messages
{
public class PacketTypeAttribute : Attribute
{
public PacketTypeAttribute(PacketType type)
{
packetType = type;
}
public PacketType packetType { get; }
}
public abstract class NetworkMessage
{
private static bool PacketTypesRegistered => PacketTypeMap.Count > 0;
internal static Dictionary<PacketType, Type> PacketTypeMap = new Dictionary<PacketType, Type>();
internal PacketType _packetType;
internal ByteEncoder byteEncoder = new ByteEncoder();
public byte[] GetBytes() => byteEncoder.ToArray();
public PacketType GetPacketType()
{
RegisterPacketTypes();
if (_packetType == PacketType.Unknown)
{
string typeName = GetType().Name;
KeyValuePair<PacketType, Type> found = PacketTypeMap.FirstOrDefault(x => x.Value.Name == typeName);
if (found.Value == null)
{
throw new Exception("Cannot find packetType for " + typeName);
}
_packetType = found.Key;
}
return _packetType;
}
public static void RegisterPacketTypes()
{
if (PacketTypesRegistered)
{
return;
}
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if (type.IsSubclassOf(typeof(NetworkMessage)))
{
PacketType? packetType = type.GetCustomAttributesData().Where(x => x.AttributeType == typeof(PacketTypeAttribute)).Select(x => (PacketType)x.ConstructorArguments[0].Value).FirstOrDefault();
PacketTypeMap[packetType.Value] = type;
}
}
}
public static NetworkMessage ParsePacket(Packet packet)
{
// find a class that can parse this packet using Reflection
// and return it
if (!PacketTypeMap.ContainsKey(packet.Info.packetType))
{
throw new Exception("No class found for packet type '" + packet.Info.packetType+"'");
}
Type type = PacketTypeMap[packet.Info.packetType];
// get the constructor that takes a Packet
ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Packet) }) ?? throw new Exception("No constructor found for type " + type.Name);
NetworkMessage networkMessage = (NetworkMessage)constructor.Invoke(new object[] { packet });
return networkMessage;
}
public Packet GetPacket(int id, ulong senderId, ulong receiverId)
{
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType());
Packet packet = new Packet(packetInfo, GetBytes());
return packet;
}
public void Broadcast()
{
Send(TransportBase.BORADCAST_ID);
}
public void Send(ulong receiverId)
{
int PacketId = Packet.GenerateId();
ulong senderId = BoneSync.lobby.GetLocalId();
Packet packet = GetPacket(PacketId, senderId, receiverId);
BoneSync.transport.Send(packet);
}
public abstract void Execute();
}
public class NetworkMessageTests
{
[Fact]
public void TestRegisterPackets()
{
NetworkMessage.RegisterPacketTypes();
Assert.NotEmpty(NetworkMessage.PacketTypeMap);
}
}
}