using System; using System.IO; using System.Numerics; using AcDream.Core.Physics; using AcDream.Core.World.Cells; using DatReaderWriter; using DatReaderWriter.Options; using DatEnvCell = DatReaderWriter.DBObjs.EnvCell; using DatEnvironment = DatReaderWriter.DBObjs.Environment; using Env = System.Environment; namespace AcDream.Core.Tests.Conformance; /// /// P0 conformance apparatus — headless load of the real Holtburg dats. /// Tests that need real cell geometry (the retail containment BSP) resolve /// the dat dir here and load cells via . Returns /// null dat dir when the dats are absent (CI) so callers can skip cleanly, /// matching DoorBugTrajectoryReplayTests.ResolveDatDir. /// /// Mirrors the proven dat-read pattern at /// DoorBugTrajectoryReplayTests.cs:184-219 + EnvCell.FromDat (EnvCell.cs:42-76). /// public static class ConformanceDats { private const uint EnvironmentFilePrefix = 0x0D000000u; // dat namespace for Environment files /// The Holtburg landblock these fixtures live in. public const uint HoltburgLandblock = 0xA9B40000u; /// Resolve the client dat directory, or null if unavailable (skip the test). public static string? ResolveDatDir() { var fromEnv = Env.GetEnvironmentVariable("ACDREAM_DAT_DIR"); if (!string.IsNullOrWhiteSpace(fromEnv) && Directory.Exists(fromEnv)) return fromEnv; var def = Path.Combine( Env.GetFolderPath(Env.SpecialFolder.UserProfile), "Documents", "Asheron's Call"); return Directory.Exists(def) ? def : null; } /// /// The conformance fixtures dir in the SOURCE tree (mirrors /// CellarUpTrajectoryReplayTests.FixtureDir — fixtures are read from source, /// not copied to the output dir). /// public static string FixturesDir => Path.Combine(SolutionRoot(), "tests", "AcDream.Core.Tests", "Conformance", "Fixtures"); private static string SolutionRoot() { var dir = AppContext.BaseDirectory; while (!string.IsNullOrEmpty(dir)) { if (File.Exists(Path.Combine(dir, "AcDream.slnx"))) return dir; dir = Path.GetDirectoryName(dir); } throw new InvalidOperationException( "Could not locate AcDream.slnx from " + AppContext.BaseDirectory); } /// The physics-verbatim cell→world transform (no +2cm render lift). public static Matrix4x4 WorldTransform(DatEnvCell datCell) => Matrix4x4.CreateFromQuaternion(datCell.Position.Orientation) * Matrix4x4.CreateTranslation(datCell.Position.Origin); /// /// Load one EnvCell from the dats with its REAL containment BSP, and register /// it into as a CellPhysics. Returns the high-level /// EnvCell (PointInCell) so a single load serves both membership predicates. /// public static EnvCell LoadEnvCell(DatCollection dats, PhysicsDataCache cache, uint cellId) { var datCell = dats.Get(cellId) ?? throw new InvalidOperationException($"EnvCell 0x{cellId:X8} not found in dats"); var environment = dats.Get(EnvironmentFilePrefix | datCell.EnvironmentId) ?? throw new InvalidOperationException($"Environment 0x{datCell.EnvironmentId:X8} not found"); if (!environment.Cells.TryGetValue(datCell.CellStructure, out var cellStruct) || cellStruct is null) throw new InvalidOperationException($"CellStruct {datCell.CellStructure} missing from environment"); var world = WorldTransform(datCell); cache.CacheCellStruct(cellId, datCell, cellStruct, world); // physics CellPhysics (real CellBSP) return EnvCell.FromDat(cellId, datCell, cellStruct, world); // render/containment EnvCell (real ContainmentBsp) } }