[TestMethod]
public void TestMessage()
{
- string test = "5 32 0 0 0 22 0 4 4 2 3 208 52 4 0 1 0 0 0 2 209 52 0 0 1 210 52 0 0 1 40 0 2 208 52 4 36 0 0 128 63 0 0 128 63 0 0 192 63 0 0 112 65 1 0 0 0 1 0 0 0 2 0 0 0 1 0 0 0 1 0 0 0 22 0 4 4 2 3 211 52 4 0 1 0 0 0 2 212 52 0 0 1 213 52 0 0 1 40 0 2 211 52 4 36 0 0 128 63 0 0 128 63 0 0 192 63 0 0 112 65 1 0 0 0 1 0 0 0 2 0 0 0 1 0 0 0 1 0 0 0";
+ string test = "5 32 0 0 0 5 0 5 255 255 255 255 15 2 0 2 2 2 9 0 1 4 110 123 233 131 255 127 255 127";
byte[] testValues = test.Replace("-", "").Split(' ').Select(b => byte.Parse(b)).ToArray();
-
-
- MessageWriter dataWriter = new MessageWriter(1024);
- dataWriter.Write((byte)5);
- dataWriter.Write(32);
- dataWriter.StartMessage(4); // Start spawn
- dataWriter.WritePacked(4); // Spawn Id = Player
- dataWriter.WritePacked(2); // Owner Id
- dataWriter.WritePacked(3); // Number children
-
- dataWriter.Write((byte)208); // NetId (packed)
- dataWriter.Write((byte)52); // NetId (packed)
-
- dataWriter.StartMessage(1); // Start data
- dataWriter.Write(""); // Name
- dataWriter.Write((byte)0); // Color
- dataWriter.Write((byte)0); // Important Flags
- dataWriter.Write((byte)2); // Player Id
- dataWriter.EndMessage();
-
- dataWriter.Write((byte)209); // NetId (packed)
- dataWriter.Write((byte)52); // NetId (packed)
-
- dataWriter.StartMessage(1); // Start data (None)
- dataWriter.EndMessage();
-
- dataWriter.Write((byte)210); // NetId (packed)
- dataWriter.Write((byte)52); // NetId (packed)
-
- dataWriter.StartMessage(1); // Start data (None)
- dataWriter.EndMessage();
-
- dataWriter.EndMessage();
-
- Console.WriteLine($"{string.Join(" ", dataWriter.Buffer.Take(dataWriter.Length))}");
- Console.WriteLine($"{string.Join(" ", testValues.Take(dataWriter.Length))}");
-
- Assert.AreEqual(22 + 4 + 1 + 3, dataWriter.Length);
-
-
MessageReader msg = MessageReader.Get(testValues, 0, testValues.Length);
- Assert.AreEqual(5, msg.Tag);
- Assert.AreEqual(32, msg.ReadInt32());
+ msg.ReadInt32();
+ msg.ReadByte();
while (msg.Position < msg.Length)
{
var sub = msg.ReadMessage();
-
+ Console.WriteLine($"Position: {msg.Position}/{msg.Length}");
+
if (sub.Tag == 4) // Spawn
{
uint spawnId = sub.ReadPackedUInt32();
- int ownerId = sub.ReadPackedInt32();
- int numChild = sub.ReadPackedInt32();
- Console.WriteLine($"Spawning {spawnId} for {ownerId} with {numChild} children");
- for (int i = 0; i < numChild; ++i)
+ if (spawnId == 4)
{
- uint childId = sub.ReadPackedUInt32();
- var childReader = sub.ReadMessage();
- if (childId == 6736)
+ int ownerId = sub.ReadPackedInt32();
+ int numChild = sub.ReadPackedInt32();
+ Console.WriteLine($"Spawning {spawnId} for {ownerId} with {numChild} children");
+ for (int i = 0; i < numChild; ++i)
{
- string name = childReader.ReadString();
- byte color = childReader.ReadByte();
- byte flags = childReader.ReadByte();
- uint playerId = childReader.ReadByte();
- Console.WriteLine($"Child {childId} has name='{name}' {color} {flags} {playerId}");
+ uint childId = sub.ReadPackedUInt32();
+ var childReader = sub.ReadMessage();
+ Console.WriteLine($"Child {childId} has data ({childReader.Tag}) len={childReader.Length}");
}
- else
+ }
+ else if (spawnId == 3)
+ {
+ int ownerId = sub.ReadPackedInt32();
+ int numChild = sub.ReadPackedInt32();
+ Console.WriteLine($"Spawning {spawnId} for {ownerId} with {numChild} children");
+ for (int i = 0; i < numChild; ++i)
{
- Console.WriteLine($"Child {childId} has data ({childReader.Tag}) len={childReader.Length}");
+ uint childId = sub.ReadPackedUInt32();
+ var childReader = sub.ReadMessage();
+
+ var gameGuid = new Guid(childReader.ReadBytesAndSize());
+ var numPlayers = childReader.ReadByte();
+ Console.WriteLine($"Child {childId} has data: {gameGuid} NumPlayers= {numPlayers}");
+ Console.WriteLine($"Remainder Data = {string.Join(" ", childReader.ReadBytes(childReader.Length - childReader.Position))}");
+
}
}
+ else
+ {
+ sub.Position = 0;
+ Console.WriteLine($"Tag: {sub.Tag}\tLength: {sub.Length}\tData = {string.Join(" ", sub.ReadBytes(sub.Length).Select(s => s.ToString()).ToArray())}");
+ }
}
else
{
+ sub.Position = 0;
Console.WriteLine($"Tag: {sub.Tag}\tLength: {sub.Length}\tData = {string.Join(" ", sub.ReadBytes(sub.Length).Select(s => s.ToString()).ToArray())}");
}
- Console.WriteLine($"Position: {msg.Position}/{msg.Length}");
}
}
{
Assert.IsTrue(MessageWriter.IsLittleEndian());
}
+
+ [TestMethod]
+ public void Test()
+ {
+ sbyte s = -1;
+ Assert.AreEqual(255, (byte)s);
+ byte b = 255;
+ Assert.AreEqual(-1, (sbyte)b);
+ }
}
}
\ No newline at end of file
/// received. The bytes and the send option that the message was sent with should be passed in to give to the
/// subscribers.
/// </remarks>
- protected void InvokeDataReceived(byte[] bytes, SendOption sendOption)
+ protected void InvokeDataReceived(byte[] bytes, SendOption sendOption, ushort reliableId)
{
DataReceivedEventArgs args = DataReceivedEventArgs.GetObject();
- args.Set(bytes, sendOption);
+ args.Set(bytes, sendOption, reliableId);
//Make a copy to avoid race condition between null check and invocation
EventHandler<DataReceivedEventArgs> handler = DataReceived;
/// </summary>
public SendOption SendOption { get; private set; }
+ public ushort ReliableId { get; private set; }
+
/// <summary>
/// Private constructor for object pool.
/// </summary>
/// </summary>
/// <param name="bytes">The bytes received.</param>
/// <param name="sendOption">The send option used to send the data.</param>
- internal void Set(byte[] bytes, SendOption sendOption)
+ internal void Set(byte[] bytes, SendOption sendOption, ushort reliableId)
{
this.Bytes = bytes;
this.SendOption = sendOption;
+ this.ReliableId = reliableId;
}
/// <inheritdoc />
}
}
+ ~UdpClientConnection()
+ {
+ this.Dispose(false);
+ }
+
/// <inheritdoc />
protected override void WriteBytesToConnection(byte[] bytes, int length)
{
try
{
socket.BeginSendTo(
- bytes,
- 0,
- length,
- SocketFlags.None,
+ bytes,
+ 0,
+ length,
+ SocketFlags.None,
RemoteEndPoint,
delegate (IAsyncResult result)
{
{
HandleDisconnect(new HazelException("Could not send data as a SocketException occured.", e));
}
- },
+ },
null
);
}
//Copy data to new array
byte[] bytes = new byte[bytesReceived];
Buffer.BlockCopy(dataBuffer, 0, bytes, 0, bytesReceived);
-
+
//Begin receiving again
try
{
//Dispose of the socket
lock (stateLock)
State = ConnectionState.NotConnected;
+ }
+ if (socket != null)
+ {
socket.Close();
+ socket.Dispose();
+ socket = null;
}
base.Dispose(disposing);
void FragmentedStartMessageReceive(byte[] buffer)
{
//Send to reliable code to send the acknowledgement
- if (!ProcessReliableReceive(buffer, 5))
+ ushort reliableId;
+ if (!ProcessReliableReceive(buffer, 5, out reliableId))
return;
ushort id = (ushort)((buffer[1] << 8) + buffer[2]);
void FragmentedMessageReceive(byte[] buffer)
{
//Send to reliable code to send the acknowledgement
- if (!ProcessReliableReceive(buffer, 5))
+ ushort reliableId;
+ if (!ProcessReliableReceive(buffer, 5, out reliableId))
return;
ushort id = (ushort)((buffer[1] << 8) + buffer[2]);
ptr += fragment.data.Length - fragment.offset;
}
- InvokeDataReceived(completeData, SendOption.FragmentedReliable);
+ InvokeDataReceived(completeData, SendOption.FragmentedReliable, 0);
}
/// <summary>
Trace.WriteLine("Resend.");
},
- resendTimeout > 0 ? resendTimeout : (AveragePingMs != 0 ? (int)AveragePingMs * 2 : 200),
+ resendTimeout > 0 ? resendTimeout : (AveragePingMs != 0 ? (int)AveragePingMs * 4 : 200),
ackCallback
);
/// <param name="buffer">The buffer received.</param>
void ReliableMessageReceive(byte[] buffer)
{
- if (ProcessReliableReceive(buffer, 1))
- InvokeDataReceived(SendOption.Reliable, buffer, 3);
+ ushort id;
+ if (ProcessReliableReceive(buffer, 1, out id))
+ InvokeDataReceived(SendOption.Reliable, buffer, 3, id);
Statistics.LogReliableReceive(buffer.Length - 3, buffer.Length);
}
/// <param name="bytes">The buffer containing the data.</param>
/// <param name="offset">The offset of the reliable header.</param>
/// <returns>Whether the packet was a new packet or not.</returns>
- bool ProcessReliableReceive(byte[] bytes, int offset)
+ bool ProcessReliableReceive(byte[] bytes, int offset, out ushort id)
{
//Get the ID form the packet
- ushort id = (ushort)((bytes[offset] << 8) + bytes[offset + 1]);
+ id = (ushort)((bytes[offset] << 8) + bytes[offset + 1]);
//Send an acknowledgement
SendAck(bytes[offset], bytes[offset + 1]);
{
//Mark items between the most recent receive and the id received as missing
for (ushort i = (ushort)(reliableReceiveLast + 1); i < id; i++)
+ {
reliableDataPacketsMissing.Add(i);
+ }
//Update the most recently received
reliableReceiveLast = id;
{
//See if we're missing it, else this packet is a duplicate as so we return false
if (!reliableDataPacketsMissing.Remove(id))
+ {
return false;
+ }
}
}
//We need to acknowledge hello messages but dont want to invoke any events!
case (byte)UdpSendOption.Hello:
- ProcessReliableReceive(buffer, 1);
+ ushort id;
+ ProcessReliableReceive(buffer, 1, out id);
Statistics.LogHelloReceive(buffer.Length);
break;
//Treat everything else as unreliable
default:
- InvokeDataReceived(SendOption.None, buffer, 1);
+ InvokeDataReceived(SendOption.None, buffer, 1, 0);
Statistics.LogUnreliableReceive(buffer.Length - 1, buffer.Length);
break;
}
/// <param name="sendOption">The send option the message was received with.</param>
/// <param name="buffer">The buffer received.</param>
/// <param name="dataOffset">The offset of data in the buffer.</param>
- void InvokeDataReceived(SendOption sendOption, byte[] buffer, int dataOffset)
+ void InvokeDataReceived(SendOption sendOption, byte[] buffer, int dataOffset, ushort reliableId)
{
byte[] dataBytes = new byte[buffer.Length - dataOffset];
Buffer.BlockCopy(buffer, dataOffset, dataBytes, 0, dataBytes.Length);
- InvokeDataReceived(dataBytes, sendOption);
+ InvokeDataReceived(dataBytes, sendOption, reliableId);
}
/// <summary>
}
}
+ ~UdpConnectionListener()
+ {
+ this.Dispose(false);
+ }
+
/// <inheritdoc />
public override void Start()
{
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
- if (disposing)
+ if (listener != null)
+ {
listener.Close();
+ this.listener.Dispose();
+ this.listener = null;
+ }
base.Dispose(disposing);
}