diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 9829470469..75f9b9f411 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 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) - 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. (#4215) - Issue where showing a `NetworkObject` with `NetworkShow` while its `NetworkVariable` updates were held back by `NetworkVariableUpdateTraits` stopped those pending changes from being sent until the variable was modified again. (#4215) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferWriter.cs index 343822fe32..3d122aa671 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()); + } + } } }