using System.Linq; using System.Numerics; using AcDream.App.Rendering; using AcDream.Content; using AcDream.Content.CharGen; using AcDream.Content.Vfx; using AcDream.Core.CharGen; using DatReaderWriter; using DatReaderWriter.Options; using Xunit; using Xunit.Abstractions; namespace AcDream.App.Tests.Rendering; /// /// Installed-DAT gate for — /// mirrors 's env-gated skip pattern /// (no unit-testable pure surface exists here the way /// has one, because THIS builder's whole job /// is resolving Setup/GfxObj/Surface/Animation dat data that /// receives pre-resolved). /// public sealed class ChargenPreviewEntityBuilderTests { private readonly ITestOutputHelper _out; public ChargenPreviewEntityBuilderTests(ITestOutputHelper output) => _out = output; [Fact] public void TryBuild_AluvianMaleDefaultSelection_ProducesANonEmptyStaticPoseEntity() { string? datDir = CornerFloodReplayTests.ResolveDatDir(); if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); using var adapter = new DatCollectionAdapter(dats); ChargenOptions options = ChargenTableReader.Load(adapter); Assert.True(options.TryGetHeritage(1u, out ChargenHeritageOptions? aluvian)); // Aluvian. Assert.True(aluvian!.GendersByKey.TryGetValue(1, out ChargenGenderOptions? male)); var catalog = new ChargenAppearanceCatalog(adapter); ChargenAppearanceSelection selection = ChargenAppearanceSelection.Default with { HairStyle = male!.HairStyles.Count > 0 ? 0u : ChargenAppearanceSelection.Unset, SkinShade = 0.5, }; bool composed = ChargenAppearanceFactory.TryCompose( options, 1u, 1, selection, catalog, catalog, out ChargenAppearanceResult appearance); Assert.True(composed); Assert.Empty(appearance.MissingPalSetIds); Assert.Empty(appearance.MissingClothingTableIds); var animations = new RetailAnimationLoader(adapter); var entity = ChargenPreviewEntityBuilder.TryBuild( adapter, animations, appearance, heritageId: 1u, Quaternion.Identity); Assert.NotNull(entity); Assert.NotEmpty(entity!.MeshRefs); Assert.Equal(appearance.SetupId, entity.SourceGfxObjOrSetupId); Assert.Equal(ChargenPreviewEntityBuilder.PreviewServerGuid, entity.ServerGuid); Assert.Equal(ChargenPreviewEntityBuilder.PreviewRenderId, entity.Id); Assert.NotNull(entity.PaletteOverride); Assert.Equal(appearance.BasePaletteId, entity.PaletteOverride!.BasePaletteId); _out.WriteLine($"setup=0x{appearance.SetupId:X8} meshRefs={entity.MeshRefs.Count} subPalettes={entity.PaletteOverride.SubPalettes.Count}"); } [Fact] public void TryBuild_UnknownSetupId_ReturnsNull() { string? datDir = CornerFloodReplayTests.ResolveDatDir(); if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); using var adapter = new DatCollectionAdapter(dats); var animations = new RetailAnimationLoader(adapter); var bogusAppearance = new ChargenAppearanceResult( SetupId: 0x0200_FFFFu, // Not a real installed Setup id. BasePaletteId: 0u, ObjDesc: ChargenObjDesc.Empty, MissingPalSetIds: [], MissingClothingTableIds: [], ClothingTablesMissingBaseEffectForSetup: []); var entity = ChargenPreviewEntityBuilder.TryBuild( adapter, animations, bogusAppearance, heritageId: 1u, Quaternion.Identity); Assert.Null(entity); } [Fact] public void TryBuild_OlthoiHeritage_ResolvesADifferentRestPoseDidThanStandardHeritages() { string? datDir = CornerFloodReplayTests.ResolveDatDir(); if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); using var adapter = new DatCollectionAdapter(dats); ChargenOptions options = ChargenTableReader.Load(adapter); Assert.True(options.TryGetHeritage(12u, out ChargenHeritageOptions? olthoi)); // Olthoi. Assert.True(olthoi!.GendersByKey.TryGetValue(1, out ChargenGenderOptions? male) || olthoi.GendersByKey.TryGetValue(2, out male)); Assert.NotNull(male); int genderKey = olthoi.GendersByKey.First(kv => ReferenceEquals(kv.Value, male)).Key; var catalog = new ChargenAppearanceCatalog(adapter); var animations = new RetailAnimationLoader(adapter); bool composed = ChargenAppearanceFactory.TryCompose( options, 12u, genderKey, ChargenAppearanceSelection.Default with { SkinShade = 0.5 }, catalog, catalog, out ChargenAppearanceResult appearance); Assert.True(composed); var entity = ChargenPreviewEntityBuilder.TryBuild( adapter, animations, appearance, heritageId: 12u, Quaternion.Identity); // Just proves the Olthoi branch doesn't throw / silently fall through to // "no mesh" — the exact pose DID differs internally (0x10000011 vs // 0x10000005) but both should still resolve a drawable mesh from Olthoi's // own Setup. Assert.NotNull(entity); Assert.NotEmpty(entity!.MeshRefs); } }