diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index c8306d1267..84a735354d 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -22,6 +22,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Issue where bits written with `BitWriter` were lost when a later `BitWriter.TryBeginWriteBits` call in the same bitwise context grew the `FastBufferWriter`. The bytes written earlier in that context were replaced with zeros or uninitialized memory. (#4225) - Issue where `NetworkTime` reported a `TickOffset` of almost a whole tick, instead of zero, for some times that land on a tick (for example 0.3 at a tick rate of 10), which put `TickWithPartial` one tick ahead or, in long sessions, `Tick` one tick behind. Times between minus one tick and zero now report tick -1 with a positive `TickOffset`, as other negative times do. (#4227) - Issue where a growable `FastBufferWriter` created with a size of 0 never returned from its first write or `TryBeginWrite` call that needed the buffer to grow. (#4223) - Issue where a `FastBufferReader` created with an offset and the default length of -1 read past the end of its source. The `ArraySegment` overload that takes an offset now applies it from the start of the segment. (#4221) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs index b3d171c5a2..e4d006f9ff 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs @@ -204,7 +204,8 @@ internal unsafe void Grow(int additionalSizeRequired) #if DEBUG UnsafeUtility.MemSet(newBuffer, 0, newSize); #endif - UnsafeUtility.MemCpy(newBuffer, Handle->BufferPointer, Length); + // Not Length: bytes written in an open bitwise context are not committed to Position until it is disposed. + UnsafeUtility.MemCpy(newBuffer, Handle->BufferPointer, Handle->Capacity); if (Handle->BufferGrew) { UnsafeUtility.Free(Handle->BufferPointer, Handle->Allocator); diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs index b4a84ff710..c98138a77c 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs @@ -329,5 +329,30 @@ public unsafe void TestWritingBitsThrowsIfTryBeginWriteNotCalled() } } + + [Test] + public void TestTryBeginWriteBitsGrowingBufferKeepsBitwiseWrites([Values] bool writeLeadingByte) + { + var writer = new FastBufferWriter(writeLeadingByte ? 2 : 1, Allocator.Temp, 16); + using (writer) + { + if (writeLeadingByte) + { + writer.WriteByteSafe(0x11); + } + + using (var bitWriter = writer.EnterBitwiseContext()) + { + Assert.IsTrue(bitWriter.TryBeginWriteBits(8)); + bitWriter.WriteBits(0xAB, 8); + // Grows the buffer while 0xAB is still uncommitted to the writer. + Assert.IsTrue(bitWriter.TryBeginWriteBits(16)); + bitWriter.WriteBits(0xCDEFUL, 16); + } + + var expected = writeLeadingByte ? new byte[] { 0x11, 0xAB, 0xEF, 0xCD } : new byte[] { 0xAB, 0xEF, 0xCD }; + CollectionAssert.AreEqual(expected, writer.ToArray()); + } + } } }