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 PacketTypeMap = new Dictionary(); 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 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); } } }