feat(content): add physical blob aliases to pak writer

This commit is contained in:
Erik 2026-07-24 13:33:53 +02:00
parent 86fadf8661
commit 0dee14765b
3 changed files with 183 additions and 2 deletions

View file

@ -170,6 +170,13 @@ public sealed class PakReader : IDisposable {
return (long)_toc[index].Offset;
}
/// <summary>Returns the immutable TOC receipt for alias/layout assertions in tests.</summary>
public PakTocEntry GetTocEntryForTest(ulong key) {
int index = BinarySearch(key);
if (index < 0) throw new KeyNotFoundException($"pak key 0x{key:X16} not found");
return _toc[index];
}
/// <summary>O(n) linear scan, used only to cross-check the binary search in tests.</summary>
public bool DebugLinearScanContainsKey(ulong key) {
for (int i = 0; i < _toc.Length; i++) {

View file

@ -18,6 +18,7 @@ public sealed class PakWriter : IDisposable {
private readonly PakHeader _headerTemplate;
private readonly List<PakTocEntry> _tocEntries = new();
private readonly HashSet<ulong> _seenKeys = new();
private readonly Dictionary<ulong, PakTocEntry> _receiptByKey = new();
private bool _finished;
public PakWriter(string path, PakHeader headerTemplate) {
@ -56,12 +57,37 @@ public sealed class PakWriter : IDisposable {
_stream.Write(bytes);
PadToAlignment();
_tocEntries.Add(new PakTocEntry {
var receipt = new PakTocEntry {
Key = key,
Offset = (ulong)offset,
Length = (uint)bytes.Length,
Crc32 = Content.Pak.Crc32.Compute(bytes),
});
};
_tocEntries.Add(receipt);
_receiptByKey.Add(key, receipt);
}
/// <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
/// offset, length, and CRC; no payload bytes are written again.
/// </summary>
public void AddAlias(ulong aliasKey, ulong existingKey) {
ThrowIfFinished();
if (aliasKey == existingKey) {
throw new ArgumentException("an alias key must differ from its source key", nameof(aliasKey));
}
if (!_receiptByKey.TryGetValue(existingKey, out var source)) {
throw new KeyNotFoundException($"source pak key 0x{existingKey:X16} has not been written");
}
if (!_seenKeys.Add(aliasKey)) {
throw new ArgumentException($"duplicate pak key 0x{aliasKey:X16}", nameof(aliasKey));
}
var alias = source;
alias.Key = aliasKey;
_tocEntries.Add(alias);
_receiptByKey.Add(aliasKey, alias);
}
/// <summary>Writes the sorted TOC and finalizes the header. Must be called exactly once.</summary>