using Theriapolis.Core.World.Generation; namespace Theriapolis.Tests; /// /// Class-level fixture that memoizes worldgen pipeline runs so multiple tests /// in the same class (all hitting e.g. seed 0xCAFEBABE) share one expensive run. /// /// Each test class gets its own WorldCache via , /// which keeps cross-class parallelism intact while collapsing within-class duplicate /// runs. A full pipeline takes ~30s; a test class that previously did 9 runs now does 1. /// /// Cache key is (seed, stageThroughIndex, variant): /// - stageThroughIndex = -1 means RunAll; otherwise RunThrough(ctx, idx). /// - variant is used by determinism tests that intentionally want TWO independent /// runs of the same seed to compare: pass variant 0 and variant 1. /// public sealed class WorldCache : IDisposable { private readonly Dictionary<(ulong Seed, int Stage, int Variant), WorldGenContext> _cache = new(); private readonly object _lock = new(); /// Full pipeline run for , memoized. public WorldGenContext Get(ulong seed, int variant = 0) => GetInternal(seed, stageThroughIndex: -1, variant); /// /// Partial pipeline run through stage index (0-based), memoized. /// E.g. GetThrough(seed, 9) runs stages 1–10 (HydrologyGen). /// public WorldGenContext GetThrough(ulong seed, int stageThroughIndex, int variant = 0) => GetInternal(seed, stageThroughIndex, variant); private WorldGenContext GetInternal(ulong seed, int stageThroughIndex, int variant) { var key = (seed, stageThroughIndex, variant); lock (_lock) { if (_cache.TryGetValue(key, out var cached)) return cached; var ctx = new WorldGenContext(seed, TestHelpers.DataDirectory); if (stageThroughIndex < 0) WorldGenerator.RunAll(ctx); else WorldGenerator.RunThrough(ctx, stageThroughIndex); _cache[key] = ctx; return ctx; } } public void Dispose() => _cache.Clear(); }