Skip to content

Commit ab58566

Browse files
author
MikMinier
committed
Fix remove message updating top level message lengths when message has a reliability header
1 parent 6c0905a commit ab58566

2 files changed

Lines changed: 338 additions & 12 deletions

File tree

Hazel.UnitTests/MessageReaderTests.cs

Lines changed: 322 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public void ReadProperFloat()
9191
}
9292

9393
[TestMethod]
94-
public void RemoveMessageWorks()
94+
public void RemoveMessageWorksForCustomMessages()
9595
{
9696
const byte Test0 = 11;
9797
const byte Test3 = 33;
@@ -146,7 +146,141 @@ public void RemoveMessageWorks()
146146
}
147147

148148
[TestMethod]
149-
public void InsertMessageWorks()
149+
public void RemoveMessageWorksForReliableMessages()
150+
{
151+
const int Test3 = 33;
152+
const uint Test4 = 44;
153+
const byte Test5 = 55;
154+
const uint Test6 = 66;
155+
const uint Test7 = 77;
156+
157+
// Test using a reliable message
158+
// This adds a sendoption header that does not fix the same header format
159+
// created by StartMessage()
160+
MessageWriter msg = MessageWriter.Get(SendOption.Reliable);
161+
162+
// Sub message 1
163+
msg.StartMessage(5);
164+
msg.Write(Test3);
165+
166+
// Sub sub message 2
167+
msg.StartMessage(2);
168+
msg.WritePacked(Test4);
169+
msg.Write(Test5);
170+
msg.WritePacked(Test6);
171+
172+
msg.EndMessage(); // End sub sub message 2
173+
msg.EndMessage(); // End sub message 1
174+
175+
// Sub message 3
176+
msg.StartMessage(9);
177+
msg.Write(Test7);
178+
msg.EndMessage(); // End sub message 3
179+
180+
// Convert to a message reader in the same way DataReceivedEventArgs
181+
// is constructed (see: UdpConnection.InvokeDataReceived())
182+
MessageReader parentReader = MessageReader.Get(msg.Buffer);
183+
parentReader.Offset = 3; // B/c reliable
184+
parentReader.Length = 20;
185+
parentReader.Position = 0;
186+
187+
// The total length is 23, but the above offsetting sets the parent reader to consider its
188+
// length to be its contents, header not included
189+
Assert.AreEqual(20, parentReader.BytesRemaining);
190+
191+
MessageReader subMessage1 = parentReader.ReadMessage();
192+
193+
Assert.AreEqual(7, parentReader.BytesRemaining);
194+
195+
_ = subMessage1.ReadInt32();
196+
MessageReader subSubMessage2 = subMessage1.ReadMessage();
197+
_ = subSubMessage2.ReadPackedUInt32();
198+
_ = subSubMessage2.ReadByte();
199+
_ = subSubMessage2.ReadPackedUInt32();
200+
Assert.AreEqual(7, parentReader.BytesRemaining);
201+
Assert.AreEqual(0, subMessage1.BytesRemaining);
202+
Assert.AreEqual(0, subSubMessage2.BytesRemaining);
203+
subMessage1.RemoveMessage(subSubMessage2);
204+
205+
// After removal, the parent should look the same
206+
Assert.AreEqual(7, parentReader.BytesRemaining);
207+
Assert.AreEqual(0, subMessage1.BytesRemaining);
208+
209+
// After removal, we can still continue reading messages
210+
MessageReader subMessage3 = parentReader.ReadMessage();
211+
uint subMessage3Value = subMessage3.ReadUInt32();
212+
213+
Assert.AreEqual(Test7, subMessage3Value);
214+
}
215+
216+
[TestMethod]
217+
public void RemoveMessageWorksForUnReliableMessages()
218+
{
219+
const int Test3 = 33;
220+
const uint Test4 = 44;
221+
const byte Test5 = 55;
222+
const uint Test6 = 66;
223+
const uint Test7 = 77;
224+
225+
// Test using an unreliable message
226+
// This adds a sendoption header that does not fix the same header format
227+
// created by StartMessage()
228+
MessageWriter msg = MessageWriter.Get(SendOption.None);
229+
230+
// Sub message 1
231+
msg.StartMessage(5);
232+
msg.Write(Test3);
233+
234+
// Sub sub message 2
235+
msg.StartMessage(2);
236+
msg.WritePacked(Test4);
237+
msg.Write(Test5);
238+
msg.WritePacked(Test6);
239+
240+
msg.EndMessage(); // End sub sub message 2
241+
msg.EndMessage(); // End sub message 1
242+
243+
// Sub message 3
244+
msg.StartMessage(9);
245+
msg.Write(Test7);
246+
msg.EndMessage(); // End sub message 3
247+
248+
MessageReader parentReader = MessageReader.Get(msg.Buffer);
249+
parentReader.Offset = 1; // B/c unreliable
250+
parentReader.Length = 20;
251+
parentReader.Position = 0;
252+
253+
// The total length is 21, but the above offsetting sets the parent reader to consider its
254+
// length to be its contents, header not included
255+
Assert.AreEqual(20, parentReader.BytesRemaining);
256+
257+
MessageReader subMessage1 = parentReader.ReadMessage();
258+
259+
Assert.AreEqual(7, parentReader.BytesRemaining);
260+
261+
_ = subMessage1.ReadInt32();
262+
MessageReader subSubMessage2 = subMessage1.ReadMessage();
263+
_ = subSubMessage2.ReadPackedUInt32();
264+
_ = subSubMessage2.ReadByte();
265+
_ = subSubMessage2.ReadPackedUInt32();
266+
Assert.AreEqual(7, parentReader.BytesRemaining);
267+
Assert.AreEqual(0, subMessage1.BytesRemaining);
268+
Assert.AreEqual(0, subSubMessage2.BytesRemaining);
269+
subMessage1.RemoveMessage(subSubMessage2);
270+
271+
// After removal, the parent should look the same
272+
Assert.AreEqual(7, parentReader.BytesRemaining);
273+
Assert.AreEqual(0, subMessage1.BytesRemaining);
274+
275+
// After removal, we can still continue reading messages
276+
MessageReader subMessage3 = parentReader.ReadMessage();
277+
uint subMessage3Value = subMessage3.ReadUInt32();
278+
279+
Assert.AreEqual(Test7, subMessage3Value);
280+
}
281+
282+
[TestMethod]
283+
public void InsertMessageWorksCustomMessages()
150284
{
151285
const byte Test0 = 11;
152286
const byte Test3 = 33;
@@ -209,6 +343,192 @@ public void InsertMessageWorks()
209343
Assert.AreEqual(Test5, five.ReadByte());
210344
}
211345

346+
[TestMethod]
347+
public void InsertMessageWorksForReliableMessages()
348+
{
349+
const int Test3 = 33;
350+
const uint Test4 = 44;
351+
const byte Test5 = 55;
352+
const uint Test6 = 66;
353+
const uint Test7 = 77;
354+
const uint Test8 = 88;
355+
356+
// Test using a reliable message
357+
// This adds a sendoption header that does not fix the same header format
358+
// created by StartMessage()
359+
MessageWriter msg = MessageWriter.Get(SendOption.Reliable);
360+
361+
// Sub message 1
362+
msg.StartMessage(5);
363+
msg.Write(Test3);
364+
365+
// Sub sub message 2
366+
msg.StartMessage(2);
367+
msg.WritePacked(Test4);
368+
msg.Write(Test5);
369+
msg.WritePacked(Test6);
370+
371+
msg.EndMessage(); // End sub sub message 2
372+
msg.EndMessage(); // End sub message 1
373+
374+
// Sub message 3
375+
msg.StartMessage(9);
376+
msg.Write(Test7);
377+
msg.EndMessage(); // End sub message 3
378+
379+
// Convert to a message reader in the same way DataReceivedEventArgs
380+
// is constructed (see: UdpConnection.InvokeDataReceived())
381+
MessageReader parentReader = MessageReader.Get(msg.Buffer);
382+
parentReader.Offset = 3; // B/c reliable
383+
parentReader.Length = 20;
384+
parentReader.Position = 0;
385+
386+
// The total length is 23, but the above offsetting sets the parent reader to consider its
387+
// length to be its contents, header not included
388+
Assert.AreEqual(20, parentReader.BytesRemaining);
389+
390+
MessageReader subMessage1 = parentReader.ReadMessage();
391+
392+
Assert.AreEqual(7, parentReader.BytesRemaining);
393+
394+
_ = subMessage1.ReadInt32();
395+
var subSubMessage2 = subMessage1.ReadMessage();
396+
_ = subSubMessage2.ReadPackedUInt32();
397+
_ = subSubMessage2.ReadByte();
398+
_ = subSubMessage2.ReadPackedUInt32();
399+
Assert.AreEqual(7, parentReader.BytesRemaining);
400+
Assert.AreEqual(0, subMessage1.BytesRemaining);
401+
Assert.AreEqual(0, subSubMessage2.BytesRemaining);
402+
403+
// Insert an internal message, which shouldn't affect the parent's read
404+
MessageWriter writer = MessageWriter.Get(SendOption.Reliable);
405+
writer.StartMessage(11);
406+
writer.Write(Test8);
407+
writer.EndMessage();
408+
409+
// Inserts writer before subSubMessage2
410+
subMessage1.InsertMessage(subSubMessage2, writer);
411+
412+
// After insert, the parent should look the same
413+
Assert.AreEqual(7, parentReader.BytesRemaining);
414+
Assert.AreEqual(0, subMessage1.BytesRemaining);
415+
416+
// After insert, we can still continue reading messages
417+
MessageReader subMessage3 = parentReader.ReadMessage();
418+
uint subMessage3Value = subMessage3.ReadUInt32();
419+
420+
Assert.AreEqual(Test7, subMessage3Value);
421+
422+
// We can now re-read from the start and read the inserted message
423+
parentReader.Position = 0;
424+
MessageReader subMessage1Again = parentReader.ReadMessage();
425+
426+
_ = subMessage1Again.ReadInt32();
427+
MessageReader insertedMessage = subMessage1Again.ReadMessage();
428+
uint insertedMessageValue = insertedMessage.ReadUInt32();
429+
430+
Assert.AreEqual(Test8, insertedMessageValue);
431+
432+
// After insert, we can still continue reading messages
433+
MessageReader subMessage3Again = parentReader.ReadMessage();
434+
uint subMessage3ValueAgain = subMessage3Again.ReadUInt32();
435+
436+
Assert.AreEqual(Test7, subMessage3ValueAgain);
437+
}
438+
439+
[TestMethod]
440+
public void InsertMessageWorksForUnReliableMessages()
441+
{
442+
const int Test3 = 33;
443+
const uint Test4 = 44;
444+
const byte Test5 = 55;
445+
const uint Test6 = 66;
446+
const uint Test7 = 77;
447+
const uint Test8 = 88;
448+
449+
// Test using an unreliable message
450+
// This adds a sendoption header that does not fix the same header format
451+
// created by StartMessage()
452+
MessageWriter msg = MessageWriter.Get(SendOption.None);
453+
454+
// Sub message 1
455+
msg.StartMessage(5);
456+
msg.Write(Test3);
457+
458+
// Sub sub message 2
459+
msg.StartMessage(2);
460+
msg.WritePacked(Test4);
461+
msg.Write(Test5);
462+
msg.WritePacked(Test6);
463+
464+
msg.EndMessage(); // End sub sub message 2
465+
msg.EndMessage(); // End sub message 1
466+
467+
// Sub message 3
468+
msg.StartMessage(9);
469+
msg.Write(Test7);
470+
msg.EndMessage(); // End sub message 3
471+
472+
// Convert to a message reader in the same way DataReceivedEventArgs
473+
// is constructed (see: UdpConnection.InvokeDataReceived())
474+
MessageReader parentReader = MessageReader.Get(msg.Buffer);
475+
parentReader.Offset = 1; // B/c unreliable
476+
parentReader.Length = 20;
477+
parentReader.Position = 0;
478+
479+
// The total length is 21, but the above offsetting sets the parent reader to consider its
480+
// length to be its contents, header not included
481+
Assert.AreEqual(20, parentReader.BytesRemaining);
482+
483+
MessageReader subMessage1 = parentReader.ReadMessage();
484+
485+
Assert.AreEqual(7, parentReader.BytesRemaining);
486+
487+
_ = subMessage1.ReadInt32();
488+
var subSubMessage2 = subMessage1.ReadMessage();
489+
_ = subSubMessage2.ReadPackedUInt32();
490+
_ = subSubMessage2.ReadByte();
491+
_ = subSubMessage2.ReadPackedUInt32();
492+
Assert.AreEqual(7, parentReader.BytesRemaining);
493+
Assert.AreEqual(0, subMessage1.BytesRemaining);
494+
Assert.AreEqual(0, subSubMessage2.BytesRemaining);
495+
496+
// Insert an internal message, which shouldn't affect the parent's read
497+
MessageWriter writer = MessageWriter.Get(SendOption.Reliable);
498+
writer.StartMessage(11);
499+
writer.Write(Test8);
500+
writer.EndMessage();
501+
502+
// Inserts writer before subSubMessage2
503+
subMessage1.InsertMessage(subSubMessage2, writer);
504+
505+
// After insert, the parent should look the same
506+
Assert.AreEqual(7, parentReader.BytesRemaining);
507+
Assert.AreEqual(0, subMessage1.BytesRemaining);
508+
509+
// After insert, we can still continue reading messages
510+
MessageReader subMessage3 = parentReader.ReadMessage();
511+
uint subMessage3Value = subMessage3.ReadUInt32();
512+
513+
Assert.AreEqual(Test7, subMessage3Value);
514+
515+
// We can now re-read from the start and read the inserted message
516+
parentReader.Position = 0;
517+
MessageReader subMessage1Again = parentReader.ReadMessage();
518+
519+
_ = subMessage1Again.ReadInt32();
520+
MessageReader insertedMessage = subMessage1Again.ReadMessage();
521+
uint insertedMessageValue = insertedMessage.ReadUInt32();
522+
523+
Assert.AreEqual(Test8, insertedMessageValue);
524+
525+
// After insert, we can still continue reading messages
526+
MessageReader subMessage3Again = parentReader.ReadMessage();
527+
uint subMessage3ValueAgain = subMessage3Again.ReadUInt32();
528+
529+
Assert.AreEqual(Test7, subMessage3ValueAgain);
530+
}
531+
212532
[TestMethod]
213533
public void InsertMessageWorksWithSendOptionNone()
214534
{

Hazel/MessageReader.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -244,20 +244,26 @@ private void AdjustLength(int offset, int amount)
244244
this.Position -= amount;
245245
}
246246

247-
if (Parent != null)
247+
this.Length -= amount;
248+
249+
if (Parent == null)
248250
{
249-
var lengthOffset = this.Offset - 3;
250-
var curLen = this.Buffer[lengthOffset]
251-
| (this.Buffer[lengthOffset + 1] << 8);
251+
// If there's no parent reference, we're at the top-most message
252+
// and this is not a normal Message, as it either contains no data, or it contains
253+
// a network reliability header
254+
return;
255+
}
252256

253-
curLen -= amount;
254-
this.Length -= amount;
257+
var lengthOffset = this.Offset - 3;
258+
var curLen = this.Buffer[lengthOffset]
259+
| (this.Buffer[lengthOffset + 1] << 8);
255260

256-
this.Buffer[lengthOffset] = (byte)curLen;
257-
this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8);
261+
curLen -= amount;
258262

259-
Parent.AdjustLength(offset, amount);
260-
}
263+
this.Buffer[lengthOffset] = (byte)curLen;
264+
this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8);
265+
266+
Parent.AdjustLength(offset, amount);
261267
}
262268

263269
public void Recycle()

0 commit comments

Comments
 (0)