using System.IO; using System.Threading.Tasks; namespace Passer.Control { public class IMessage { public IMessage() { } public IMessage(byte[] buffer) { Deserialize(buffer); } public virtual byte[] Serialize() { return null; } public virtual void Deserialize(byte[] buffer) { } public static bool SendMsg(Client client, IMessage msg) { return SendMsg(client, msg.Serialize()); } public static bool SendMsg(Client client, byte[] buffer) { if (client == null || client.ipAddress == null) return false; client.udpClient.Send(buffer, buffer.Length, client.ipAddress, client.port); return true; } public static bool PublishMsg(Client client, IMessage msg) { return PublishMsg(client, msg.Serialize()); } public static bool PublishMsg(Client client, byte[] buffer) { if (client == null) return false; client.udpClient.Send(buffer, buffer.Length, "127.0.0.1", client.port); return true; } public static async Task Receive(Stream dataStream, byte packetSize) { byte[] buffer = new byte[packetSize - 1]; // without msgId int byteCount = dataStream.Read(buffer, 0, packetSize - 1); while (byteCount < packetSize - 1) { // not all bytes have been read, wait and try again await Task.Delay(1); byteCount += dataStream.Read(buffer, byteCount, packetSize - 1 - byteCount); } return buffer; } } #region Client public class ClientMsg : IMessage { public const byte Id = 0xA0; public const byte length = 2; public byte networkId; public ClientMsg(byte networkId) { this.networkId = networkId; } public ClientMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[ClientMsg.length]; buffer[0] = ClientMsg.Id; buffer[1] = networkId; return buffer; } public override void Deserialize(byte[] buffer) { base.Deserialize(buffer); uint ix = 0; networkId = buffer[ix]; } public static bool Send(Client client, byte networkId) { ClientMsg msg = new(networkId); return SendMsg(client, msg); } public static bool Publish(Client client, byte networkId) { ClientMsg msg = new(networkId); return PublishMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); ClientMsg msg = new(buffer); if (client.networkId == 0) { client.networkId = (byte)(Client.clients.Count); NetworkIdMsg.Send(client, client.networkId); client.messageQueue.Enqueue(msg); } else if (msg.networkId == 0) { NetworkIdMsg.Send(client, client.networkId); client.messageQueue.Enqueue(msg); } return true; } } #endregion Client #region Network Id public class NetworkIdMsg : IMessage { public const byte Id = 0xA1; public const byte length = 2; public byte networkId; NetworkIdMsg(byte networkId) { this.networkId = networkId; } NetworkIdMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[NetworkIdMsg.length]; buffer[0] = NetworkIdMsg.Id; buffer[1] = this.networkId; return buffer; } public override void Deserialize(byte[] buffer) { uint ix = 0; this.networkId = buffer[ix]; } public static bool Send(Client client, byte networkId) { NetworkIdMsg msg = new(networkId); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); NetworkIdMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Network Id #region Investigate public class InvestigateMsg : IMessage { public const byte Id = 0x81; public const byte length = 3; public byte networkId; public byte thingId; public InvestigateMsg(byte networkId, byte thingId) { this.networkId = networkId; this.thingId = thingId; } public InvestigateMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[InvestigateMsg.length]; buffer[0] = InvestigateMsg.Id; buffer[1] = this.networkId; buffer[2] = this.thingId; return buffer; } public override void Deserialize(byte[] buffer) { uint ix = 0; this.networkId = buffer[ix++]; this.thingId = buffer[ix++]; } public static bool Send(Client client, byte thingId) { InvestigateMsg msg = new(client.networkId, thingId); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); InvestigateMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Investigate #region Thing public class ThingMsg : IMessage { public const byte length = 5; public const byte Id = 0x80; public byte networkId; public byte thingId; public byte thingType; public byte parentId; public ThingMsg(byte networkId, byte thingId, byte thingType, byte parentId) { this.thingId = thingId; this.thingType = thingType; this.parentId = parentId; } public ThingMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[ThingMsg.length]; byte ix = 0; buffer[ix++] = ThingMsg.Id; buffer[ix++] = this.networkId; buffer[ix++] = this.thingId; buffer[ix++] = this.thingType; buffer[ix] = this.parentId; return buffer; } public override void Deserialize(byte[] buffer) { uint ix = 0; this.networkId = buffer[ix++]; this.thingId = buffer[ix++]; this.thingType = buffer[ix++]; this.parentId = buffer[ix]; } public static bool Send(Client client, byte thingId, byte thingType, byte parentId) { ThingMsg msg = new(client.networkId, thingId, thingType, parentId); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); ThingMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Thing #region Name public class NameMsg : IMessage { public const byte Id = 0x91; // 145 public const byte length = 4; public byte networkId; public byte thingId; public byte len; public string name; public NameMsg(byte networkId, byte thingId, string name) { this.networkId = networkId; this.thingId = thingId; this.name = name; } public NameMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[length + this.name.Length]; byte ix = 0; buffer[ix++] = NameMsg.Id; buffer[ix++] = this.networkId; buffer[ix++] = this.thingId; buffer[ix++] = (byte)this.name.Length; for (int nameIx = 0; nameIx < this.name.Length; nameIx++, ix++) buffer[ix] = (byte)this.name[nameIx]; return buffer; } public override void Deserialize(byte[] buffer) { uint ix = 0; this.thingId = buffer[ix++]; int strlen = buffer[ix++]; this.name = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, strlen); } public static bool Send(Client client, byte thingId, string name) { NameMsg msg = new(client.networkId, thingId, name); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { byte[] buffer = await Receive(dataStream, packetSize); NameMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion #region Model URL public class ModelUrlMsg : IMessage { public const byte Id = 0x90; // (144) Model URL public byte networkId; public byte thingId; public Spherical position; public float scale; public string url; public ModelUrlMsg(byte networkId, byte thingId, string url, float scale = 1) { this.networkId = networkId; this.thingId = thingId; this.url = url; this.scale = scale; this.position = Spherical.zero; } public ModelUrlMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[this.url.Length + 6]; byte ix = 0; buffer[ix++] = ModelUrlMsg.Id; buffer[ix++] = this.networkId; buffer[ix++] = this.thingId; // Thing Id LowLevelMessages.SendFloat16(buffer, ref ix, new float16(1.0f)); buffer[ix++] = (byte)url.Length; for (int urlIx = 0; urlIx < this.url.Length; urlIx++, ix++) buffer[ix] = (byte)url[urlIx]; return buffer; } public override void Deserialize(byte[] buffer) { byte ix = 0; this.networkId = buffer[ix++]; this.thingId = buffer[ix++]; this.scale = LowLevelMessages.ReceiveFloat16(buffer, ref ix); int strlen = buffer[ix++]; url = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, strlen); } public static bool Send(Client client, byte thingId, string modelUrl) { ModelUrlMsg msg = new(client.networkId, thingId, modelUrl); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { byte[] buffer = await Receive(dataStream, packetSize); ModelUrlMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Model URL #region Pose public class PoseMsg : IMessage { public const byte Id = 0x10; public const byte length = 4 + 4 + 4; public byte networkId; public byte thingId; public byte poseType; public const byte Pose_Position = 0x01; public const byte Pose_Orientation = 0x02; public Spherical position; public Quat32 orientation; public PoseMsg(byte networkId, byte thingId, Spherical position, Quat32 orientation) { this.networkId = networkId; this.thingId = thingId; this.position = position; this.orientation = orientation; this.poseType = 0; if (this.position != null) this.poseType |= Pose_Position; else this.position = new Spherical(0, 0, 0); if (this.orientation != null) this.poseType |= Pose_Orientation; else this.orientation = new Quat32(0, 0, 0, 1); } public PoseMsg(byte[] buffer) : base(buffer) { } public override byte[] Serialize() { byte[] buffer = new byte[PoseMsg.length]; byte ix = 0; buffer[ix++] = PoseMsg.Id; buffer[ix++] = this.networkId; buffer[ix++] = this.thingId; buffer[ix++] = this.poseType; LowLevelMessages.SendSpherical(buffer, ref ix, this.position); LowLevelMessages.SendQuat32(buffer, ref ix, this.orientation); return buffer; } public override void Deserialize(byte[] buffer) { byte ix = 0; this.networkId = buffer[ix++]; this.thingId = buffer[ix++]; this.poseType = buffer[ix++]; //if ((poseType & Pose_Position) != 0) this.position = LowLevelMessages.ReceiveSpherical(buffer, ref ix); //if ((poseType & Pose_Orientation) != 0) { this.orientation = LowLevelMessages.ReceiveQuat32(buffer, ref ix); } public static bool Send(Client client, byte thingId, Spherical position, Quat32 orientation) { PoseMsg msg = new(client.networkId, thingId, position, orientation); return SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); PoseMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Pose #region Custom public class CustomMsg : IMessage { public const byte Id = 0xB1; public byte networkId; public byte thingId; public byte[] bytes; public CustomMsg(byte[] buffer) : base(buffer) { } public CustomMsg(byte networkId, byte thingId, byte[] bytes) : base() { this.networkId = networkId; this.thingId = thingId; this.bytes = bytes; } public override byte[] Serialize() { byte[] buffer = new byte[4 + this.bytes.Length]; byte ix = 0; buffer[ix++] = CustomMsg.Id; buffer[ix++] = this.networkId; buffer[ix++] = this.thingId; buffer[ix++] = (byte)bytes.Length; foreach (byte b in bytes) buffer[ix++] = b; return buffer; } public override void Deserialize(byte[] buffer) { uint ix = 0; this.networkId = buffer[ix++]; this.thingId = buffer[ix++]; byte length = buffer[ix++]; this.bytes = new byte[length]; for (uint bytesIx = 0; ix < length; ix++, bytesIx++) this.bytes[bytesIx] = buffer[ix]; } public static void Send(Client client, byte thingId, byte[] bytes) { CustomMsg msg = new(client.networkId, thingId, bytes); SendMsg(client, msg); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { byte[] buffer = await Receive(dataStream, packetSize); CustomMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Custom #region Text public class TextMsg : IMessage { public const byte Id = 0xB0; public string text; public TextMsg(byte[] buffer) : base(buffer) { } public override void Deserialize(byte[] buffer) { uint ix = 0; uint strlen = buffer[ix++]; this.text = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, (int)strlen); } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { byte[] buffer = await Receive(dataStream, packetSize); TextMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion #region Destroy public class DestroyMsg : IMessage { public const byte Id = 0x20; public const byte length = 2; public byte networkId; public byte thingId; public DestroyMsg(byte[] buffer) : base(buffer) { } public override void Deserialize(byte[] buffer) { this.networkId = buffer[0]; this.thingId = buffer[1]; } public static async Task Receive(Stream dataStream, Client client, byte packetSize) { if (packetSize != length) return false; byte[] buffer = await Receive(dataStream, packetSize); DestroyMsg msg = new(buffer); client.messageQueue.Enqueue(msg); return true; } } #endregion Destroy }