Use universal packed resource resolution

This commit is contained in:
gamer147
2026-07-21 20:23:32 -04:00
parent 5f816bb438
commit 1a2ea008c6
19 changed files with 161 additions and 154 deletions

View File

@@ -75,7 +75,7 @@ public class AgfDecoderTests
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var store = new Sys4AssetStore(catalog, Paths.GameDir, Paths.GameDir);
var resources = new ResourceMap(catalog, store);
Assert.Equal("SO001.AGF", resources.ResolveTexture("SC0000", 0x337e)?.Name);
Assert.Equal("SO001.AGF", resources.ResolveTexture(0x337e)?.Name);
var image = AgfDecoder.Decode(store, catalog.ResolveRaw(0x337e)!);
Assert.Equal((800, 300), (image.Width, image.Height));
Assert.Contains(image.Pixels.Where((_, i) => (i & 3) == 3), a => a is > 0 and < 255);
@@ -89,7 +89,7 @@ public class AgfDecoderTests
public void InstalledFieldMapSheetsResolveAndDecodeByRawCatalogIndex(int rawId, string name)
{
var resources = ResourceMap.Load();
var asset = resources.ResolveRawTexture(rawId);
var asset = resources.ResolveTexture(rawId);
Assert.NotNull(asset);
Assert.Equal(name, asset.Name);
var image = resources.DecodeTexture(asset);

View File

@@ -15,7 +15,6 @@ public class CallScriptTests
{
public virtual void EnterScriptContext(string scriptName) { }
public virtual void ExitScriptContext() { }
public virtual long ResolveTextureResourceId(long resourceId) => resourceId;
public void ShowText(int o, string t) { }
public void WaitForInput() { }
public void Sleep(long duration) { }
@@ -52,9 +51,6 @@ public class CallScriptTests
Events.Add($"exit:{_contexts.Pop()}");
}
public override long ResolveTextureResourceId(long resourceId)
=> resourceId + (_contexts.Peek() == "CALLEE" ? 700 : 70);
public override void SetTexture(long resourceId, int slot) => Textures.Add((resourceId, slot));
}
@@ -133,7 +129,7 @@ public class CallScriptTests
}
[Fact]
public void ScriptLocalTextureIdsFollowTheActiveNestedFrame()
public void PackedTextureIdsRemainUnchangedAcrossNestedFrames()
{
var t = Table();
var callee = Asm(t, "CALLEE",
@@ -149,7 +145,7 @@ public class CallScriptTests
vm.Run();
Assert.Equal(new[] { (77L, 1), (707L, 2), (77L, 3) }, host.Textures);
Assert.Equal(new[] { (7L, 1), (7L, 2), (7L, 3) }, host.Textures);
Assert.Equal(new[] { "enter:CALLER", "enter:CALLEE", "exit:CALLEE", "exit:CALLER" }, host.Events);
}
}

View File

@@ -126,7 +126,7 @@ public class GfxCommandBufferTests
}
[Fact]
public void RawTextureLoadBypassesSceneResourceNormalizationAndFeedsRetainedDraws()
public void ModeOneTextureLoadPreservesPackedIdAndFeedsRetainedDraws()
{
var t = T();
var scene = ScriptAssembler.Assemble(t, "RAW-GFX", new List<(int, Operand[])>
@@ -135,7 +135,7 @@ public class GfxCommandBufferTests
(0x1fb, new[] { I(0x100), I(0x3e), I(0), I(0), I(100), I(100), I(20), I(30) }),
Exit(),
}, System.Array.Empty<string>());
var host = new RecordingHost { TextureResourceIdOffset = 0x1000 };
var host = new RecordingHost();
var vm = new VirtualMachine(scene, t, host);
vm.Run();

View File

@@ -342,7 +342,7 @@ public class HistoryInteractionOpsTests
Assert.Equal(new[] { (expectedVoice, checked((int)expectedVariant)) }, host.VoiceRequests);
var resources = ResourceMap.Load();
var voice = Assert.IsType<AssetEntry>(resources.Resolve("SC0000", expectedVoice));
var voice = Assert.IsType<AssetEntry>(resources.ResolveVoice(expectedVoice));
Assert.Equal("MAN999.OGG", voice.Name);
Assert.NotEmpty(resources.ReadAudio(voice).Bytes);
}

View File

@@ -196,7 +196,7 @@ public class MovieOpcodeTests
{
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var resources = new ResourceMap(catalog, new Sys4AssetStore(catalog, Paths.GameDir));
var entry = resources.Resolve("SC0000", 0x33);
var entry = resources.ResolveMovie(0x33);
Assert.Equal("CHAPTER.AGF", entry?.Name);
var movie = resources.ReadMovie(entry!);
@@ -207,11 +207,11 @@ public class MovieOpcodeTests
[Theory]
[InlineData(0x335f, "LOGO.AGF")]
[InlineData(0x3364, "OP.AGF")]
public void ModalMoviePayloadResolvesFromUniversalRawCatalog(int rawId, string expectedName)
public void ModalMoviePayloadResolvesFromUniversalPackedCatalog(int resourceId, string expectedName)
{
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var resources = new ResourceMap(catalog, new Sys4AssetStore(catalog, Paths.GameDir));
var entry = resources.ResolveRawMovie(rawId);
var entry = resources.ResolveMovie(resourceId);
Assert.Equal(expectedName, entry?.Name);
var movie = resources.ReadMovie(entry!);
@@ -224,7 +224,7 @@ public class MovieOpcodeTests
if (!OperatingSystem.IsWindows()) return;
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var resources = new ResourceMap(catalog, new Sys4AssetStore(catalog, Paths.GameDir));
var entry = resources.Resolve("SC0000", 0x33)!;
var entry = resources.ResolveMovie(0x33)!;
using var decoder = new DirectShowMovieDecoder(resources.ReadMovie(entry));
Assert.True(decoder.StopTimeMs > 0, "DirectShow should expose a positive IMediaPosition stop time");

View File

@@ -22,6 +22,7 @@ public class Sys4AssetStoreTests
Assert.All(append.Files, entry =>
{
Assert.Equal(1, entry.PackId);
Assert.Equal(0x01000000 | entry.RawIndex, entry.PackedId);
Assert.StartsWith("$1$", entry.Name);
Assert.Equal("APPEND01.ALF", entry.Archive);
});
@@ -178,14 +179,14 @@ public class Sys4AssetStoreTests
Assert.Equal("BGM005.OGG", bgm?.Name);
AssertOgg(resources.ReadAudio(bgm!));
var voice = resources.ResolveVoice("SC0000", 0x24);
var voice = resources.ResolveVoice(0x24);
Assert.Equal("MAN999.OGG", voice?.Name);
AssertOgg(resources.ReadAudio(voice!));
var roomVoice = resources.ResolveVoice("ROOM", 0x3365);
var roomVoice = resources.ResolveVoice(0x3365);
Assert.Equal("EUA0016.OGG", roomVoice?.Name);
AssertOgg(resources.ReadAudio(roomVoice!));
Assert.Null(resources.ResolveVoice("ROOM", 0x337e)); // SO001.AGF is not voice audio.
Assert.Null(resources.ResolveVoice(0x337e)); // SO001.AGF is not voice audio.
var sfx = resources.ResolveSoundEffect(0x28);
Assert.Equal("E0808.WAV", sfx?.Name);
@@ -194,7 +195,6 @@ public class Sys4AssetStoreTests
Assert.Equal("RIFF", Encoding.ASCII.GetString(wav.Bytes, 0, 4));
Assert.Equal("WAVE", Encoding.ASCII.GetString(wav.Bytes, 8, 4));
Assert.Null(resources.Resolve("TITLE", 0x2aea));
Assert.Equal("SE020.WAV", resources.ResolveSoundEffect(0x2aea)?.Name);
Assert.Equal("SE013.WAV", resources.ResolveSoundEffect(0x2aeb)?.Name);
Assert.Equal("SE015.WAV", resources.ResolveSoundEffect(0x3321)?.Name);
@@ -204,6 +204,33 @@ public class Sys4AssetStoreTests
Assert.Throws<InvalidDataException>(() => resources.ReadAudio(catalog.ResolveName("SO001.AGF")!));
}
[Fact]
public void Sc0010LowOperandsAreAlreadyUniversalPackedIds()
{
var resources = ResourceMap.Load();
Assert.Equal("SO013A.AGF", resources.ResolveTexture(0x21)?.Name);
Assert.Equal("LILA1414.OGG", resources.ResolveVoice(0x120)?.Name);
Assert.Equal("LILB0053.OGG", resources.ResolveVoice(0x121)?.Name);
Assert.Equal("LILC0054.OGG", resources.ResolveVoice(0x122)?.Name);
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
Assert.Equal("COL0023.OGG", catalog.ResolveRaw(0x11e + 0x21)?.Name);
}
[Fact]
public void TypedResourceResolutionPreservesAppendPackSelector()
{
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var resources = new ResourceMap(catalog);
var append = Assert.Single(catalog.AppendPacks).Value;
var texture = Assert.Single(append.Files.Where(entry =>
entry.Name.EndsWith(".AGF", StringComparison.OrdinalIgnoreCase)).Take(1));
Assert.Same(texture, resources.ResolveTexture(texture.PackedId));
Assert.NotEqual(texture, resources.ResolveTexture(texture.RawIndex));
}
[Fact]
public void AllInstalledLooseScriptOverridesShadowArchiveCopies()
{

View File

@@ -55,9 +55,7 @@ internal class RecordingHost : IHost
public readonly List<bool> AdvPagePresentationSuspended = new();
public int CursorClearCount;
public int SceneContextResets;
public long TextureResourceIdOffset;
public void ReportWarning(string message) => Warnings.Add(message);
public long ResolveTextureResourceId(long resourceId) => resourceId + TextureResourceIdOffset;
public void ShowText(int offset, string text) => Lines.Add((offset, text));
public void SetAdvTextCursor(int layoutSlot, int x, int y) => TextCursors.Add((layoutSlot, x, y));
public void DrawStringToSurface(int surfaceSlot, int x, int y, string text)
@@ -162,8 +160,8 @@ internal class RecordingHost : IHost
return MovieStopTimeMs;
}
public bool IsMovieSurfaceActive(int surfaceSlot) => ActiveMovieSurfaces.Contains(surfaceSlot);
public void PlayModalMovieToSurface(long rawResourceId, int surfaceSlot, long movieFlags)
=> ModalMovies.Add((rawResourceId, surfaceSlot, movieFlags));
public void PlayModalMovieToSurface(long resourceId, int surfaceSlot, long movieFlags)
=> ModalMovies.Add((resourceId, surfaceSlot, movieFlags));
}
internal sealed class MapProvider : IScriptProvider