using System.Collections.Immutable; using AcDream.App.Physics; using AcDream.Content; using AcDream.Content.Pak; using AcDream.Core.Physics; using DatReaderWriter.DBObjs; using DatReaderWriter.Enums; using DatReaderWriter.Types; namespace AcDream.App.Tests.Physics; public sealed class LiveCollisionAssetPublisherTests { [Fact] public void LiveGfxAndSetup_PublishExactPreparedViewOnce() { const uint GfxId = 0x0100_0042u; const uint SetupId = 0x0200_0042u; var cache = new PhysicsDataCache(); var source = new RecordingSource(); var publisher = new LiveCollisionAssetPublisher(cache, source); GfxObj gfx = PhysicsGfx(); var setup = new Setup(); publisher.CacheGfxObj(GfxId, gfx); publisher.CacheGfxObj(GfxId, gfx); publisher.CacheSetup(SetupId, setup); publisher.CacheSetup(SetupId, setup); Assert.Same(source.Gfx, cache.GetFlatGfxObj(GfxId)); Assert.Same( source.Gfx.PhysicsBsp, cache.GetGfxObj(GfxId)!.FlatPhysicsBsp); Assert.Same(source.Setup, cache.GetFlatSetup(SetupId)); Assert.Same( source.Setup, cache.GetSetup(SetupId)!.FlatCollision); Assert.Equal(1, source.GfxReads); Assert.Equal(1, source.SetupReads); } [Fact] public void VisualOnlyGfx_RemembersPreparedEmptyAssetWithoutGraphRecord() { const uint GfxId = 0x0100_0043u; var cache = new PhysicsDataCache(); var source = new RecordingSource(); var publisher = new LiveCollisionAssetPublisher(cache, source); var gfx = new GfxObj(); publisher.CacheGfxObj(GfxId, gfx); publisher.CacheGfxObj(GfxId, gfx); Assert.Null(cache.GetGfxObj(GfxId)); Assert.Same(source.Gfx, cache.GetFlatGfxObj(GfxId)); Assert.Equal(1, source.GfxReads); } [Fact] public void MissingPreparedAsset_RejectsGraphOnlyLivePublication() { var cache = new PhysicsDataCache(); var source = new RecordingSource { GfxResult = PreparedCollisionReadResult .Missing, }; var publisher = new LiveCollisionAssetPublisher(cache, source); InvalidDataException fault = Assert.Throws( () => publisher.CacheGfxObj(0x0100_0044u, PhysicsGfx())); Assert.Contains("Missing", fault.Message, StringComparison.Ordinal); Assert.Equal(0, cache.GfxObjCount); Assert.Equal(0, cache.FlatGfxObjCount); } private static GfxObj PhysicsGfx() => new() { Flags = GfxObjFlags.HasPhysics, PhysicsBSP = new PhysicsBSPTree { Root = new PhysicsBSPNode { Type = BSPNodeType.Leaf, }, }, VertexArray = new VertexArray(), PhysicsPolygons = new Dictionary(), }; private sealed class RecordingSource : IPreparedCollisionSource { private static readonly FlatPhysicsBsp EmptyPhysics = new( -1, ImmutableArray.Empty, ImmutableArray.Empty, FlatPolygonTable.Empty); public FlatGfxObjCollisionAsset Gfx { get; } = new(EmptyPhysics, null, null); public FlatSetupCollision Setup { get; } = new( ImmutableArray.Empty, ImmutableArray.Empty, 0f, 0f, 0f, 0f); public int GfxReads { get; private set; } public int SetupReads { get; private set; } public PreparedCollisionReadResult? GfxResult { get; init; } public PreparedAssetPresence ProbeCollision( PakAssetType type, uint sourceFileId) => PreparedAssetPresence.Available; public PreparedCollisionReadResult ReadGfxObjCollision( uint sourceFileId, CancellationToken cancellationToken = default) { GfxReads++; return GfxResult ?? PreparedCollisionReadResult .Loaded(Gfx); } public PreparedCollisionReadResult ReadSetupCollision( uint sourceFileId, CancellationToken cancellationToken = default) { SetupReads++; return PreparedCollisionReadResult .Loaded(Setup); } public PreparedCollisionReadResult ReadCellStructureCollision( uint sourceFileId, CancellationToken cancellationToken = default) => PreparedCollisionReadResult .Missing; public PreparedCollisionReadResult ReadEnvCellTopology( uint sourceFileId, CancellationToken cancellationToken = default) => PreparedCollisionReadResult.Missing; public PreparedCollisionSourceStats CollisionStats => default; public void Dispose() { } } }