diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 27bf78002a..0028e619de 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -25,6 +25,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. (#4226) - 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. (#4224) - 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. (#4222) - Issue where a client synchronized while a `NetworkList` still had unsent changes applied those changes twice, resulting in duplicate entries and index-based events landing on the wrong elements on that client. (#4216) 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 dfc3f5caf4..4c8b41ecb9 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()); + } + } } }