Resolve exact SetSurface blend, alpha-test, and fog state once during extraction and preserve it through recipe-10 prepared payloads, Wb/EnvCell command data, Vulkan pipelines, push constants, and both ordinary/atmospheric one-pass shaders. Preserve AP-240 Wb pure-Clip immediate opaque/A2C while EnvCell uses retail premultiplied Clip; detail-off routing remains unchanged. Correct AP-232 and register the remaining detail-off state divergence. Mutation first failures (all restored): - raw Add->SRCALPHA/ONE: WalkStaticStreamPopulatorTests.ImmediateBuildingDetail_UsesExactResolvedSetSurfaceState line 1278, expected wb-mesh-raw-additive-1x. - inverse-add->alpha-add: same test line 1278, expected wb-mesh-inverse-additive-1x. - remove Env inverse: EnvCellAlphaDrawSourceTests.DetailOn_EveryEnvCellFamilyDrawsOnceInPlaceWithAuthoredOpacity line 132, expected envcell-inverse. - raw IsAdditive precedence: same test line 132, Translucent|Clip|Additive expected envcell-alpha. - Wb paletted ParamB=0: OrderPreservingSubmitterTests line 333, expected 0.392156869. - Wb DDS ParamB=0.05: same test line 333, expected 0.784313738. - disable Alpha+Clip test: WalkStaticStreamPopulatorTests line 1286, expected 0.784313738. - always fog raw Add: same test line 1287, expected no-fog true. - disable fog non-Add: same test line 1287, expected no-fog false. - X=a*qA: RetailDetailTextureContractTests line 261, shared squared-alpha substring absent. - X includes base alpha: same test line 262, forbidden baseTexel.a present. - CLIP uses 0.05: EnvCellAlphaDrawSourceTests.ClipShaders_UseGreaterEqualForThePerRangeReference line 367. - second detail draw: EnvCell detail-on line 131, collection contained 2 draws. - straight-alpha substitute: Wb immediate line 1278, expected wb-mesh-additive-1x. - omit ordered detail arm: OrderPreservingSubmitterTests line 318, expected (77,3.5), got (0,0). - omit atmospheric combine: RetailDetailTextureContractTests line 260, shared include absent. - drop serialized opacity: ObjectMeshDataSerializerTests line 292, expected opacity bits, got 1.0. - stale detail arm: atmospheric adjacency line 402, expected slot 0, got 77. - per-frame surface map: EnvCell warmed allocation line 285, expected 0 B, got 204800 B.
156 lines
6.1 KiB
C#
156 lines
6.1 KiB
C#
using System.IO;
|
|
using AcDream.Content.Pak;
|
|
|
|
namespace AcDream.Content.Tests;
|
|
|
|
public class PakFormatTests {
|
|
[Fact]
|
|
public void Header_Size_Is64Bytes() {
|
|
Assert.Equal(64, PakHeader.Size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// S5-c4 fix round 1: recipe 10 carries exact SetSurface state after
|
|
/// recipe 10's resolved SetSurface state after recipe 9's authored opacity.
|
|
/// It remains a payload recipe change.
|
|
/// </summary>
|
|
[Fact]
|
|
public void FormatVersion_StaysAtTwo_AcrossTheS5C4RecipeBump() {
|
|
Assert.Equal(2u, PakFormat.CurrentFormatVersion);
|
|
Assert.Equal(10u, PakFormat.CurrentBakeToolVersion);
|
|
}
|
|
|
|
[Fact]
|
|
public void TocEntry_Size_Is24Bytes() {
|
|
Assert.Equal(24, PakTocEntry.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_Magic_IsAcpkLittleEndian() {
|
|
// 'A'=0x41 'C'=0x43 'P'=0x50 'K'=0x4B — little-endian dword reads
|
|
// back as 0x4B504341 per the normative spec.
|
|
Assert.Equal(0x4B504341u, PakHeader.MagicValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_WriteThenRead_RoundTripsEveryField() {
|
|
var header = new PakHeader {
|
|
FormatVersion = 1,
|
|
PortalIteration = 111,
|
|
CellIteration = 222,
|
|
HighResIteration = 333,
|
|
LanguageIteration = 444,
|
|
TocOffset = 0x1_0000_0002UL,
|
|
TocCount = 777,
|
|
BakeToolVersion = 1,
|
|
};
|
|
|
|
using var ms = new MemoryStream();
|
|
header.WriteTo(ms);
|
|
Assert.Equal(PakHeader.Size, ms.Length);
|
|
|
|
ms.Position = 0;
|
|
var readBack = PakHeader.ReadFrom(ms);
|
|
|
|
Assert.Equal(PakHeader.MagicValue, readBack.Magic);
|
|
Assert.Equal(header.FormatVersion, readBack.FormatVersion);
|
|
Assert.Equal(header.PortalIteration, readBack.PortalIteration);
|
|
Assert.Equal(header.CellIteration, readBack.CellIteration);
|
|
Assert.Equal(header.HighResIteration, readBack.HighResIteration);
|
|
Assert.Equal(header.LanguageIteration, readBack.LanguageIteration);
|
|
Assert.Equal(header.TocOffset, readBack.TocOffset);
|
|
Assert.Equal(header.TocCount, readBack.TocCount);
|
|
Assert.Equal(header.BakeToolVersion, readBack.BakeToolVersion);
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_ReadFrom_Span_RoundTrips() {
|
|
var header = new PakHeader {
|
|
FormatVersion = 1,
|
|
PortalIteration = 5,
|
|
CellIteration = 6,
|
|
HighResIteration = 7,
|
|
LanguageIteration = 8,
|
|
TocOffset = 999,
|
|
TocCount = 3,
|
|
BakeToolVersion = 1,
|
|
};
|
|
Span<byte> buf = stackalloc byte[PakHeader.Size];
|
|
header.WriteTo(buf);
|
|
var readBack = PakHeader.ReadFrom((ReadOnlySpan<byte>)buf);
|
|
Assert.Equal(header.CellIteration, readBack.CellIteration);
|
|
Assert.Equal(header.TocOffset, readBack.TocOffset);
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_ReservedBytes_AreZero() {
|
|
var header = new PakHeader { FormatVersion = 1, BakeToolVersion = 1 };
|
|
Span<byte> buf = stackalloc byte[PakHeader.Size];
|
|
header.WriteTo(buf);
|
|
// offset 40, length 24 per the normative layout
|
|
for (int i = 40; i < 64; i++) {
|
|
Assert.Equal(0, buf[i]);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_FieldOffsets_MatchNormativeLayout() {
|
|
var header = new PakHeader {
|
|
FormatVersion = 0x11111111,
|
|
PortalIteration = 0x22222222,
|
|
CellIteration = 0x33333333,
|
|
HighResIteration = 0x44444444,
|
|
LanguageIteration = 0x55555555,
|
|
TocOffset = 0x6666666677777777UL,
|
|
TocCount = 0x88888888,
|
|
BakeToolVersion = 0x99999999,
|
|
};
|
|
Span<byte> buf = stackalloc byte[PakHeader.Size];
|
|
header.WriteTo(buf);
|
|
|
|
Assert.Equal(PakHeader.MagicValue, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[0..4]));
|
|
Assert.Equal(0x11111111u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[4..8]));
|
|
Assert.Equal(0x22222222u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[8..12]));
|
|
Assert.Equal(0x33333333u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[12..16]));
|
|
Assert.Equal(0x44444444u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[16..20]));
|
|
Assert.Equal(0x55555555u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[20..24]));
|
|
Assert.Equal(0x6666666677777777UL, System.Buffers.Binary.BinaryPrimitives.ReadUInt64LittleEndian(buf[24..32]));
|
|
Assert.Equal(0x88888888u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[32..36]));
|
|
Assert.Equal(0x99999999u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[36..40]));
|
|
}
|
|
|
|
[Fact]
|
|
public void TocEntry_WriteThenRead_RoundTrips() {
|
|
var entry = new PakTocEntry {
|
|
Key = PakKey.Compose(PakAssetType.GfxObjMesh, 0x010002B4u),
|
|
Offset = 0x4000,
|
|
Length = 12345,
|
|
Crc32 = 0xDEADBEEF,
|
|
};
|
|
Span<byte> buf = stackalloc byte[PakTocEntry.Size];
|
|
entry.WriteTo(buf);
|
|
var readBack = PakTocEntry.ReadFrom((ReadOnlySpan<byte>)buf);
|
|
|
|
Assert.Equal(entry.Key, readBack.Key);
|
|
Assert.Equal(entry.Offset, readBack.Offset);
|
|
Assert.Equal(entry.Length, readBack.Length);
|
|
Assert.Equal(entry.Crc32, readBack.Crc32);
|
|
}
|
|
|
|
[Fact]
|
|
public void TocEntry_FieldOffsets_MatchNormativeLayout() {
|
|
var entry = new PakTocEntry {
|
|
Key = 0x1111111122222222UL,
|
|
Offset = 0x3333333344444444UL,
|
|
Length = 0x55555555,
|
|
Crc32 = 0x66666666,
|
|
};
|
|
Span<byte> buf = stackalloc byte[PakTocEntry.Size];
|
|
entry.WriteTo(buf);
|
|
|
|
Assert.Equal(0x1111111122222222UL, System.Buffers.Binary.BinaryPrimitives.ReadUInt64LittleEndian(buf[0..8]));
|
|
Assert.Equal(0x3333333344444444UL, System.Buffers.Binary.BinaryPrimitives.ReadUInt64LittleEndian(buf[8..16]));
|
|
Assert.Equal(0x55555555u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[16..20]));
|
|
Assert.Equal(0x66666666u, System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(buf[20..24]));
|
|
}
|
|
}
|