fix: Fixes BitArray serialization (#2170)

Fixes serialization/deserialization edge cases with BitArray. If you use BitArray, you will need to migrate.

1. Change the type in the migration JSON file (if there is one) from `BitArray` to `byte[]` for all the versions you need to migrate.
2. Then in the `MigrateFrom`, use the following function to convert the field from a byte[] back to the BitArray.

Example Migration JSON:
```json
    {
      "name": "RestrictedSpells",
      "type": "byte[]",
      "rule": "ArrayMigrationRule",
      "ruleArguments": [
        "byte",
        "PrimitiveTypeMigrationRule",
        ""
      ]
    },
```

Migration function to use in MigrateFrom:
```cs
public static BitArray MigrateBitArray(byte[] data, int bitLength) => new(data) { Length = bitLength };
```

Example use:
```cs
    private void MigrateFrom(V0Content content)
    {
        // ... deserialize
        _restrictedSpells = content.RestrictedSpells.MigrateBitArray(SpellRegistry.Types.Length);
        _restrictedSkills = content.RestrictedSkills.MigrateBitArray(SkillInfo.Table.Length);
        // ... rest of deserialize
    }

```
This commit is contained in:
Kamron Batman 2025-04-30 19:33:15 -07:00
parent 1eeeabb729
commit 5cb97cc6de
No known key found for this signature in database
GPG key ID: 7D81DF26D9A5D94A
2 changed files with 27 additions and 14 deletions

View file

@ -14,6 +14,7 @@
*************************************************************************/
using System;
using System.Buffers;
using System.Collections;
using System.IO;
using System.Net;
@ -51,7 +52,7 @@ public interface IGenericReader
var delta => new DateTime(delta + DateTime.UtcNow.Ticks, DateTimeKind.Utc)
};
}
decimal ReadDecimal() => new(stackalloc int[4] { ReadInt(), ReadInt(), ReadInt(), ReadInt() });
decimal ReadDecimal() => new([ReadInt(), ReadInt(), ReadInt(), ReadInt()]);
int ReadEncodedInt()
{
int v = 0, shift = 0;
@ -119,14 +120,19 @@ public interface IGenericReader
public BitArray ReadBitArray()
{
var byteArrayLength = ReadEncodedInt();
int bitLength = ReadEncodedInt();
int byteLength = (bitLength + 7) / 8;
// We need an exact array size since the ctor doesn't allow for offset/length, not much we can do at this point.
var byteArray = new byte[byteArrayLength];
Read(byteArray);
return new BitArray(byteArray);
var buffer = ArrayPool<byte>.Shared.Rent(byteLength);
try
{
Read(buffer.AsSpan(0, byteLength));
return new BitArray(buffer) { Length = bitLength };
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}
TextDefinition ReadTextDefinition()

View file

@ -163,14 +163,21 @@ public interface IGenericWriter
public void Write(BitArray bitArray)
{
var bytesLength = (bitArray.Length - 1 + (1 << 3)) >>> 3;
var arrayBuffer = ArrayPool<byte>.Shared.Rent(bytesLength);
int bitLength = bitArray.Length;
int byteLength = (bitLength + 7) / 8;
WriteEncodedInt(bytesLength);
bitArray.CopyTo(arrayBuffer, 0);
WriteEncodedInt(bitLength);
Write(arrayBuffer.AsSpan(0, bytesLength));
ArrayPool<byte>.Shared.Return(arrayBuffer);
var arrayBuffer = ArrayPool<byte>.Shared.Rent(byteLength);
try
{
bitArray.CopyTo(arrayBuffer, 0);
Write(arrayBuffer.AsSpan(0, byteLength));
}
finally
{
ArrayPool<byte>.Shared.Return(arrayBuffer);
}
}
void Write(TextDefinition def)