[Ampr] Fix PakDirectoryTracker to handle multiple directories with the same name (#925)

This commit is contained in:
Berk 2026-09-28 04:43:05 +03:00 committed by GitHub
parent b4c065a0b0
commit a9e1c25968
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 1 deletions

View File

@ -60,10 +60,19 @@ internal static class PakDirectoryTracker
// related assets, and the guest streams them with locality, so disambiguate collisions
// by choosing the unconsumed match nearest the running read cursor.
DirectoryEntry? best = null;
DirectoryEntry? uniqueMatch = null;
var matchCount = 0;
var bestDistance = ulong.MaxValue;
foreach (var entry in entries)
{
if (entry.Consumed || entry.FileLen != requestedSize)
if (entry.FileLen != requestedSize)
{
continue;
}
uniqueMatch = entry;
matchCount++;
if (entry.Consumed)
{
continue;
}
@ -90,6 +99,12 @@ internal static class PakDirectoryTracker
return best.FilePos;
}
// A unique archive member may be opened again after its first read.
if (matchCount == 1)
{
return uniqueMatch!.FilePos;
}
}
return state.NextOffset;

View File

@ -72,6 +72,23 @@ public sealed class PakDirectoryTrackerTests
Assert.Equal(0x1000UL + (runLen * 2), third);
}
[Fact]
public void ResolveSequentialOffset_UniqueEntryCanBeReadAgain()
{
const uint fileId = 0x5AA5_0003;
const uint size = 15903;
var memory = new FakeCpuMemory(0x1_0000_0000, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
LoadDirectory(ctx, fileId, memory, 0x1_0000_0000, dirFileOffset: 0x400, new[]
{
new PakEntry("bots/characters.txt", FilePos: 0xF81CF, FileLen: size),
});
Assert.Equal(0xF81CFUL, PakDirectoryTracker.ResolveSequentialOffset(fileId, size));
PakDirectoryTracker.OnReadCompleted(ctx, fileId, destination: 0x1_0000_0000, fileOffset: 0xF81CF, bytesRead: size);
Assert.Equal(0xF81CFUL, PakDirectoryTracker.ResolveSequentialOffset(fileId, size));
}
// Feeds the tracker a synthetic PACK header + directory table exactly as the AMPR read path does:
// first the 12-byte header (which arms directory parsing), then the directory records themselves.
private static void LoadDirectory(