fix: Fixes flaky tests, formatting, and sequential testing. (#2168)

This commit is contained in:
Kamron Batman 2025-04-30 16:42:38 -07:00 • committed by GitHub
parent 415c7a6bfd
commit 7dbfc9d161
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 1304 additions and 1289 deletions

View file

@ -11,7 +11,8 @@ using Xunit;
namespace UOContent.Tests;
public class BoatPacketTests : IClassFixture<ServerFixture>
[Collection("Sequential UOContent Tests")]
public class BoatPacketTests
{
[Theory]
[InlineData(Direction.West, 10, 100, 200)]

View file

@ -15,117 +15,117 @@ public sealed class MoveBoatHS : Packet
int yOffset
) : base(0xF6)
{
EnsureCapacity(3 + 15 + ents.Count * 10);
EnsureCapacity(3 + 15 + ents.Count * 10);
Stream.Write(boat.Serial);
Stream.Write((byte)speed);
Stream.Write((byte)d);
Stream.Write((byte)boat.Facing);
Stream.Write((short)(boat.X + xOffset));
Stream.Write((short)(boat.Y + yOffset));
Stream.Write((short)boat.Z);
Stream.Write((short)0); // count placeholder
Stream.Write(boat.Serial);
Stream.Write((byte)speed);
Stream.Write((byte)d);
Stream.Write((byte)boat.Facing);
Stream.Write((short)(boat.X + xOffset));
Stream.Write((short)(boat.Y + yOffset));
Stream.Write((short)boat.Z);
Stream.Write((short)0); // count placeholder
var count = 0;
var count = 0;
foreach (var ent in ents)
{
Stream.Write(ent.Serial);
Stream.Write((short)(ent.X + xOffset));
Stream.Write((short)(ent.Y + yOffset));
Stream.Write((short)ent.Z);
++count;
}
Stream.Seek(16, SeekOrigin.Begin);
Stream.Write((short)count);
foreach (var ent in ents)
{
Stream.Write(ent.Serial);
Stream.Write((short)(ent.X + xOffset));
Stream.Write((short)(ent.Y + yOffset));
Stream.Write((short)ent.Z);
++count;
}
Stream.Seek(16, SeekOrigin.Begin);
Stream.Write((short)count);
}
}
public sealed class DisplayBoatHS : Packet
{
public DisplayBoatHS(Mobile beholder, BaseBoat boat) : base(0xF7)
{
var ents = boat.GetMovingEntities(true);
var ents = boat.GetMovingEntities(true);
EnsureCapacity(3 + 2 + 5 * 26);
EnsureCapacity(3 + 2 + 5 * 26);
Stream.Write((short)0); // count placeholder
Stream.Write((short)0); // count placeholder
var count = 0;
var count = 0;
foreach (var ent in ents)
foreach (var ent in ents)
{
if (!beholder.CanSee(ent))
{
if (!beholder.CanSee(ent))
{
continue;
}
// Embedded WorldItemHS packets
Stream.Write((byte)0xF3);
Stream.Write((short)0x1);
if (ent is BaseMulti bm)
{
Stream.Write((byte)0x02);
Stream.Write(bm.Serial);
// TODO: Mask no longer needed, merge with Item case?
Stream.Write((ushort)(bm.ItemID & 0x3FFF));
Stream.Write((byte)0);
Stream.Write((short)bm.Amount);
Stream.Write((short)bm.Amount);
Stream.Write((short)(bm.X & 0x7FFF));
Stream.Write((short)(bm.Y & 0x3FFF));
Stream.Write((sbyte)bm.Z);
Stream.Write((byte)bm.Light);
Stream.Write((short)bm.Hue);
Stream.Write((byte)bm.GetPacketFlags());
}
else if (ent is Mobile m)
{
Stream.Write((byte)0x01);
Stream.Write(m.Serial);
Stream.Write((short)m.Body);
Stream.Write((byte)0);
Stream.Write((short)1);
Stream.Write((short)1);
Stream.Write((short)(m.X & 0x7FFF));
Stream.Write((short)(m.Y & 0x3FFF));
Stream.Write((sbyte)m.Z);
Stream.Write((byte)m.Direction);
Stream.Write((short)m.Hue);
Stream.Write((byte)m.GetPacketFlags(true));
}
else if (ent is Item item)
{
Stream.Write((byte)0x00);
Stream.Write(item.Serial);
Stream.Write((ushort)(item.ItemID & 0xFFFF));
Stream.Write((byte)0);
Stream.Write((short)item.Amount);
Stream.Write((short)item.Amount);
Stream.Write((short)(item.X & 0x7FFF));
Stream.Write((short)(item.Y & 0x3FFF));
Stream.Write((sbyte)item.Z);
Stream.Write((byte)item.Light);
Stream.Write((short)item.Hue);
Stream.Write((byte)item.GetPacketFlags());
}
Stream.Write((short)0x00);
++count;
continue;
}
Stream.Seek(3, SeekOrigin.Begin);
Stream.Write((short)count);
// Embedded WorldItemHS packets
Stream.Write((byte)0xF3);
Stream.Write((short)0x1);
if (ent is BaseMulti bm)
{
Stream.Write((byte)0x02);
Stream.Write(bm.Serial);
// TODO: Mask no longer needed, merge with Item case?
Stream.Write((ushort)(bm.ItemID & 0x3FFF));
Stream.Write((byte)0);
Stream.Write((short)bm.Amount);
Stream.Write((short)bm.Amount);
Stream.Write((short)(bm.X & 0x7FFF));
Stream.Write((short)(bm.Y & 0x3FFF));
Stream.Write((sbyte)bm.Z);
Stream.Write((byte)bm.Light);
Stream.Write((short)bm.Hue);
Stream.Write((byte)bm.GetPacketFlags());
}
else if (ent is Mobile m)
{
Stream.Write((byte)0x01);
Stream.Write(m.Serial);
Stream.Write((short)m.Body);
Stream.Write((byte)0);
Stream.Write((short)1);
Stream.Write((short)1);
Stream.Write((short)(m.X & 0x7FFF));
Stream.Write((short)(m.Y & 0x3FFF));
Stream.Write((sbyte)m.Z);
Stream.Write((byte)m.Direction);
Stream.Write((short)m.Hue);
Stream.Write((byte)m.GetPacketFlags(true));
}
else if (ent is Item item)
{
Stream.Write((byte)0x00);
Stream.Write(item.Serial);
Stream.Write((ushort)(item.ItemID & 0xFFFF));
Stream.Write((byte)0);
Stream.Write((short)item.Amount);
Stream.Write((short)item.Amount);
Stream.Write((short)(item.X & 0x7FFF));
Stream.Write((short)(item.Y & 0x3FFF));
Stream.Write((sbyte)item.Z);
Stream.Write((byte)item.Light);
Stream.Write((short)item.Hue);
Stream.Write((byte)item.GetPacketFlags());
}
Stream.Write((short)0x00);
++count;
}
}
Stream.Seek(3, SeekOrigin.Begin);
Stream.Write((short)count);
}
}

View file

@ -14,66 +14,66 @@ public class HousePacketTests
[InlineData(0x1001u)]
public void TestBeginHouseCustomization(uint serial)
{
var expected = new BeginHouseCustomization((Serial)serial).Compile();
var expected = new BeginHouseCustomization((Serial)serial).Compile();
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendBeginHouseCustomization((Serial)serial);
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendBeginHouseCustomization((Serial)serial);
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
}
[Theory]
[InlineData(0x1001u)]
public void TestEndHouseCustomization(uint serial)
{
var expected = new EndHouseCustomization((Serial)serial).Compile();
var expected = new EndHouseCustomization((Serial)serial).Compile();
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendEndHouseCustomization((Serial)serial);
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendEndHouseCustomization((Serial)serial);
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
}
[Theory]
[InlineData(0x1001u, 0)]
[InlineData(0x1001u, 100)]
public void TestDesignStateGeneral(uint serial, int revision)
{
var expected = new DesignStateGeneral((Serial)serial, revision).Compile();
var expected = new DesignStateGeneral((Serial)serial, revision).Compile();
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendDesignStateGeneral((Serial)serial, revision);
var ns = PacketTestUtilities.CreateTestNetState();
ns.SendDesignStateGeneral((Serial)serial, revision);
var result = ns.SendPipe.Reader.AvailableToRead();
AssertThat.Equal(result, expected);
}
}
[Fact]
public void TestHouseDesignStateDetailed()
{
Serial serial = (Serial)0x40000001;
var revision = 10;
var tiles = new MultiTileEntry[250];
for (var i = 0; i < tiles.Length; i++)
{
tiles[i] = new MultiTileEntry(
(ushort)i,
(byte)i,
(byte)i,
(byte)(i / 50),
TileFlag.None
);
}
var mcl = new MultiComponentList(tiles.ToList());
var expected = new DesignStateDetailed(
serial, revision, mcl.Min.X, mcl.Min.Y, mcl.Max.X, mcl.Max.Y, tiles
).Compile();
var actual = HousePackets.CreateHouseDesignStateDetailed(serial, revision, mcl);
AssertThat.Equal(actual, expected);
Serial serial = (Serial)0x40000001;
var revision = 10;
var tiles = new MultiTileEntry[250];
for (var i = 0; i < tiles.Length; i++)
{
tiles[i] = new MultiTileEntry(
(ushort)i,
(byte)i,
(byte)i,
(byte)(i / 50),
TileFlag.None
);
}
}
var mcl = new MultiComponentList(tiles.ToList());
var expected = new DesignStateDetailed(
serial, revision, mcl.Min.X, mcl.Min.Y, mcl.Max.X, mcl.Max.Y, tiles
).Compile();
var actual = HousePackets.CreateHouseDesignStateDetailed(serial, revision, mcl);
AssertThat.Equal(actual, expected);
}
}

View file

@ -3,320 +3,319 @@ using System.Buffers;
using System.IO;
using Server.Compression;
namespace Server.Network
namespace Server.Network;
public class BeginHouseCustomization : Packet
{
public class BeginHouseCustomization : Packet
public BeginHouseCustomization(Serial house) : base(0xBF)
{
public BeginHouseCustomization(Serial house) : base(0xBF)
{
EnsureCapacity(17);
EnsureCapacity(17);
Stream.Write((short)0x20);
Stream.Write(house);
Stream.Write((byte)0x04);
Stream.Write((ushort)0x0000);
Stream.Write((ushort)0xFFFF);
Stream.Write((ushort)0xFFFF);
Stream.Write((byte)0xFF);
Stream.Write((short)0x20);
Stream.Write(house);
Stream.Write((byte)0x04);
Stream.Write((ushort)0x0000);
Stream.Write((ushort)0xFFFF);
Stream.Write((ushort)0xFFFF);
Stream.Write((byte)0xFF);
}
}
public class EndHouseCustomization : Packet
{
public EndHouseCustomization(Serial house) : base(0xBF)
{
EnsureCapacity(17);
Stream.Write((short)0x20);
Stream.Write(house);
Stream.Write((byte)0x05);
Stream.Write((ushort)0x0000);
Stream.Write((ushort)0xFFFF);
Stream.Write((ushort)0xFFFF);
Stream.Write((byte)0xFF);
}
}
public sealed class DesignStateGeneral : Packet
{
public DesignStateGeneral(Serial house, int revision) : base(0xBF)
{
EnsureCapacity(13);
Stream.Write((short)0x1D);
Stream.Write(house);
Stream.Write(revision);
}
}
public sealed class DesignStateDetailed : Packet
{
public const int MaxItemsPerStairBuffer = 750;
private readonly bool[] m_PlaneUsed = new bool[9];
private readonly byte[] m_PrimBuffer = new byte[4];
public DesignStateDetailed(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles)
: base(0xD8)
{
EnsureCapacity(17 + tiles.Length * 5);
Write((byte)0x03); // Compression Type
Write((byte)0x00); // Unknown
Write(serial.Value);
Write(revision);
Write((short)tiles.Length);
Write((short)0); // Buffer length : reserved
Write((byte)0); // Plane count : reserved
var totalLength = 1; // includes plane count
var width = xMax - xMin + 1;
var height = yMax - yMin + 1;
var planeBuffers = new byte[9][];
for (var i = 0; i < planeBuffers.Length; ++i)
{
planeBuffers[i] = ArrayPool<byte>.Shared.Rent(0x400);
}
var stairBuffers = new byte[6][];
for (var i = 0; i < stairBuffers.Length; ++i)
{
stairBuffers[i] = ArrayPool<byte>.Shared.Rent(MaxItemsPerStairBuffer * 5);
}
Clear(planeBuffers[0], width * height * 2);
for (var i = 0; i < 4; ++i)
{
Clear(planeBuffers[1 + i], (width - 1) * (height - 2) * 2);
Clear(planeBuffers[5 + i], width * (height - 1) * 2);
}
var totalStairsUsed = 0;
for (var i = 0; i < tiles.Length; ++i)
{
var mte = tiles[i];
var x = mte.OffsetX - xMin;
var y = mte.OffsetY - yMin;
int z = mte.OffsetZ;
var floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0;
int plane, size;
switch (z)
{
case 0:
plane = 0;
break;
case 7:
plane = 1;
break;
case 27:
plane = 2;
break;
case 47:
plane = 3;
break;
case 67:
plane = 4;
break;
default:
{
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
var stairBuffer = stairBuffers[stairBufferIndex];
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
stairBuffer[byteIndex++] = (byte)mte.ItemId;
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
++totalStairsUsed;
continue;
}
}
if (plane == 0)
{
size = height;
}
else if (floor)
{
size = height - 2;
x -= 1;
y -= 1;
}
else
{
size = height - 1;
plane += 4;
}
var index = (x * size + y) * 2;
if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400)
{
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
var stairBuffer = stairBuffers[stairBufferIndex];
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
stairBuffer[byteIndex++] = (byte)mte.ItemId;
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
++totalStairsUsed;
}
else
{
m_PlaneUsed[plane] = true;
planeBuffers[plane][index] = (byte)(mte.ItemId >> 8);
planeBuffers[plane][index + 1] = (byte)mte.ItemId;
}
}
var planeCount = 0;
var deflatedBuffer = ArrayPool<byte>.Shared.Rent(0x2000);
for (var i = 0; i < planeBuffers.Length; ++i)
{
if (!m_PlaneUsed[i])
{
ArrayPool<byte>.Shared.Return(planeBuffers[i]);
continue;
}
++planeCount;
int size = i switch
{
0 => width * height * 2,
< 5 => (width - 1) * (height - 2) * 2,
_ => width * (height - 1) * 2
};
var inflatedBuffer = planeBuffers[i];
var deflatedLength = Deflate.Standard.Pack(
deflatedBuffer,
inflatedBuffer.AsSpan(0, size)
);
if (deflatedLength == 0)
{
Console.WriteLine("Compression error");
}
Write((byte)(0x20 | i));
Write((byte)size);
Write((byte)deflatedLength);
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
Write(deflatedBuffer, 0, deflatedLength);
totalLength += 4 + deflatedLength;
ArrayPool<byte>.Shared.Return(inflatedBuffer);
}
var totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;
for (var i = 0; i < totalStairBuffersUsed; ++i)
{
++planeCount;
var count = Math.Min(MaxItemsPerStairBuffer, totalStairsUsed - i * MaxItemsPerStairBuffer);
var size = count * 5;
var inflatedBuffer = stairBuffers[i];
var deflatedLength = Deflate.Standard.Pack(
deflatedBuffer,
inflatedBuffer.AsSpan(0, size)
);
if (deflatedLength == 0)
{
Console.WriteLine("Compression error");
}
Write((byte)(9 + i));
Write((byte)size);
Write((byte)deflatedLength);
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
Write(deflatedBuffer, 0, deflatedLength);
totalLength += 4 + deflatedLength;
}
for (var i = 0; i < stairBuffers.Length; ++i)
{
ArrayPool<byte>.Shared.Return(stairBuffers[i]);
}
ArrayPool<byte>.Shared.Return(deflatedBuffer);
Stream.Seek(15, SeekOrigin.Begin);
Write((short)totalLength); // Buffer length
Write((byte)planeCount); // Plane count
}
public class EndHouseCustomization : Packet
public void Write(int value)
{
public EndHouseCustomization(Serial house) : base(0xBF)
{
EnsureCapacity(17);
m_PrimBuffer[0] = (byte)(value >> 24);
m_PrimBuffer[1] = (byte)(value >> 16);
m_PrimBuffer[2] = (byte)(value >> 8);
m_PrimBuffer[3] = (byte)value;
Stream.Write((short)0x20);
Stream.Write(house);
Stream.Write((byte)0x05);
Stream.Write((ushort)0x0000);
Stream.Write((ushort)0xFFFF);
Stream.Write((ushort)0xFFFF);
Stream.Write((byte)0xFF);
}
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
}
public sealed class DesignStateGeneral : Packet
public void Write(uint value)
{
public DesignStateGeneral(Serial house, int revision) : base(0xBF)
{
EnsureCapacity(13);
m_PrimBuffer[0] = (byte)(value >> 24);
m_PrimBuffer[1] = (byte)(value >> 16);
m_PrimBuffer[2] = (byte)(value >> 8);
m_PrimBuffer[3] = (byte)value;
Stream.Write((short)0x1D);
Stream.Write(house);
Stream.Write(revision);
}
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
}
public sealed class DesignStateDetailed : Packet
public void Write(short value)
{
public const int MaxItemsPerStairBuffer = 750;
m_PrimBuffer[0] = (byte)(value >> 8);
m_PrimBuffer[1] = (byte)value;
private readonly bool[] m_PlaneUsed = new bool[9];
private readonly byte[] m_PrimBuffer = new byte[4];
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2);
}
public DesignStateDetailed(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles)
: base(0xD8)
public void Write(byte value)
{
Stream.UnderlyingStream.WriteByte(value);
}
public void Write(byte[] buffer, int offset, int size)
{
Stream.UnderlyingStream.Write(buffer, offset, size);
}
public static void Clear(byte[] buffer, int size)
{
for (var i = 0; i < size; ++i)
{
EnsureCapacity(17 + tiles.Length * 5);
Write((byte)0x03); // Compression Type
Write((byte)0x00); // Unknown
Write(serial.Value);
Write(revision);
Write((short)tiles.Length);
Write((short)0); // Buffer length : reserved
Write((byte)0); // Plane count : reserved
var totalLength = 1; // includes plane count
var width = xMax - xMin + 1;
var height = yMax - yMin + 1;
var planeBuffers = new byte[9][];
for (var i = 0; i < planeBuffers.Length; ++i)
{
planeBuffers[i] = ArrayPool<byte>.Shared.Rent(0x400);
}
var stairBuffers = new byte[6][];
for (var i = 0; i < stairBuffers.Length; ++i)
{
stairBuffers[i] = ArrayPool<byte>.Shared.Rent(MaxItemsPerStairBuffer * 5);
}
Clear(planeBuffers[0], width * height * 2);
for (var i = 0; i < 4; ++i)
{
Clear(planeBuffers[1 + i], (width - 1) * (height - 2) * 2);
Clear(planeBuffers[5 + i], width * (height - 1) * 2);
}
var totalStairsUsed = 0;
for (var i = 0; i < tiles.Length; ++i)
{
var mte = tiles[i];
var x = mte.OffsetX - xMin;
var y = mte.OffsetY - yMin;
int z = mte.OffsetZ;
var floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0;
int plane, size;
switch (z)
{
case 0:
plane = 0;
break;
case 7:
plane = 1;
break;
case 27:
plane = 2;
break;
case 47:
plane = 3;
break;
case 67:
plane = 4;
break;
default:
{
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
var stairBuffer = stairBuffers[stairBufferIndex];
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
stairBuffer[byteIndex++] = (byte)mte.ItemId;
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
++totalStairsUsed;
continue;
}
}
if (plane == 0)
{
size = height;
}
else if (floor)
{
size = height - 2;
x -= 1;
y -= 1;
}
else
{
size = height - 1;
plane += 4;
}
var index = (x * size + y) * 2;
if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400)
{
var stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
var stairBuffer = stairBuffers[stairBufferIndex];
var byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8);
stairBuffer[byteIndex++] = (byte)mte.ItemId;
stairBuffer[byteIndex++] = (byte)mte.OffsetX;
stairBuffer[byteIndex++] = (byte)mte.OffsetY;
stairBuffer[byteIndex] = (byte)mte.OffsetZ;
++totalStairsUsed;
}
else
{
m_PlaneUsed[plane] = true;
planeBuffers[plane][index] = (byte)(mte.ItemId >> 8);
planeBuffers[plane][index + 1] = (byte)mte.ItemId;
}
}
var planeCount = 0;
var deflatedBuffer = ArrayPool<byte>.Shared.Rent(0x2000);
for (var i = 0; i < planeBuffers.Length; ++i)
{
if (!m_PlaneUsed[i])
{
ArrayPool<byte>.Shared.Return(planeBuffers[i]);
continue;
}
++planeCount;
int size = i switch
{
0 => width * height * 2,
< 5 => (width - 1) * (height - 2) * 2,
_ => width * (height - 1) * 2
};
var inflatedBuffer = planeBuffers[i];
var deflatedLength = Deflate.Standard.Pack(
deflatedBuffer,
inflatedBuffer.AsSpan(0, size)
);
if (deflatedLength == 0)
{
Console.WriteLine("Compression error");
}
Write((byte)(0x20 | i));
Write((byte)size);
Write((byte)deflatedLength);
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
Write(deflatedBuffer, 0, deflatedLength);
totalLength += 4 + deflatedLength;
ArrayPool<byte>.Shared.Return(inflatedBuffer);
}
var totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;
for (var i = 0; i < totalStairBuffersUsed; ++i)
{
++planeCount;
var count = Math.Min(MaxItemsPerStairBuffer, totalStairsUsed - i * MaxItemsPerStairBuffer);
var size = count * 5;
var inflatedBuffer = stairBuffers[i];
var deflatedLength = Deflate.Standard.Pack(
deflatedBuffer,
inflatedBuffer.AsSpan(0, size)
);
if (deflatedLength == 0)
{
Console.WriteLine("Compression error");
}
Write((byte)(9 + i));
Write((byte)size);
Write((byte)deflatedLength);
Write((byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));
Write(deflatedBuffer, 0, deflatedLength);
totalLength += 4 + deflatedLength;
}
for (var i = 0; i < stairBuffers.Length; ++i)
{
ArrayPool<byte>.Shared.Return(stairBuffers[i]);
}
ArrayPool<byte>.Shared.Return(deflatedBuffer);
Stream.Seek(15, SeekOrigin.Begin);
Write((short)totalLength); // Buffer length
Write((byte)planeCount); // Plane count
}
public void Write(int value)
{
m_PrimBuffer[0] = (byte)(value >> 24);
m_PrimBuffer[1] = (byte)(value >> 16);
m_PrimBuffer[2] = (byte)(value >> 8);
m_PrimBuffer[3] = (byte)value;
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
}
public void Write(uint value)
{
m_PrimBuffer[0] = (byte)(value >> 24);
m_PrimBuffer[1] = (byte)(value >> 16);
m_PrimBuffer[2] = (byte)(value >> 8);
m_PrimBuffer[3] = (byte)value;
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4);
}
public void Write(short value)
{
m_PrimBuffer[0] = (byte)(value >> 8);
m_PrimBuffer[1] = (byte)value;
Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2);
}
public void Write(byte value)
{
Stream.UnderlyingStream.WriteByte(value);
}
public void Write(byte[] buffer, int offset, int size)
{
Stream.UnderlyingStream.Write(buffer, offset, size);
}
public static void Clear(byte[] buffer, int size)
{
for (var i = 0; i < size; ++i)
{
buffer[i] = 0;
}
buffer[i] = 0;
}
}
}