feat(content): bake and read flat collision assets

Append strict collision/topology payloads to the existing prepared package so later physics cutover can drop parsed DAT graphs without adding a second mapping or changing traversal behavior. The full 2,232,170-key catalog is deterministic across worker counts, exact-byte aliased, corruption-isolated, and cancellation-safe.
This commit is contained in:
Erik 2026-07-25 15:22:08 +02:00
parent d9300c7854
commit 9cd42417a8
29 changed files with 2868 additions and 63 deletions

View file

@ -46,28 +46,51 @@ public sealed class PakWriter : IDisposable {
/// </summary>
public void AddBlob(ulong key, ObjectMeshData data) {
ThrowIfFinished();
if (!_seenKeys.Add(key)) {
throw new ArgumentException($"duplicate pak key 0x{key:X16}", nameof(key));
}
ReserveKey(key);
long offset = _stream.Position;
using var ms = new MemoryStream();
ObjectMeshDataSerializer.Write(data, ms);
var bytes = ms.ToArray();
AddReservedBlob(key, bytes);
}
/// <summary>
/// Adds an already serialized immutable payload. This is the package seam
/// used by typed non-render assets such as flat collision records.
/// </summary>
public void AddBlob(ulong key, ReadOnlySpan<byte> bytes) {
ThrowIfFinished();
ReserveKey(key);
AddReservedBlob(key, bytes);
}
private void AddReservedBlob(ulong key, ReadOnlySpan<byte> bytes) {
if ((ulong)bytes.Length > uint.MaxValue) {
throw new ArgumentException(
"one pak payload cannot exceed UInt32.MaxValue bytes",
nameof(bytes));
}
long offset = _stream.Position;
_stream.Write(bytes);
PadToAlignment();
var receipt = new PakTocEntry {
Key = key,
Offset = (ulong)offset,
Length = (uint)bytes.Length,
Length = checked((uint)bytes.Length),
Crc32 = Content.Pak.Crc32.Compute(bytes),
};
_tocEntries.Add(receipt);
_receiptByKey.Add(key, receipt);
}
private void ReserveKey(ulong key) {
if (!_seenKeys.Add(key)) {
throw new ArgumentException($"duplicate pak key 0x{key:X16}", nameof(key));
}
}
/// <summary>
/// Adds a second independently addressable key for an existing physical
/// blob. The alias receives a normal TOC row with the source blob's exact