using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using AcDream.Content;
using DatReaderWriter;
using DatReaderWriter.Enums;
using DatReaderWriter.Lib.IO;
namespace AcDream.Content.Tests;
///
/// Adapts to for
/// MeshExtractor's constructor, scoped to the equivalence test suite. A
/// third copy alongside AcDream.App.Rendering.Wb.DatCollectionAdapter
/// (internal to AcDream.App) and AcDream.Bake.BakeDatCollectionAdapter
/// (internal to AcDream.Bake) — tests live in the project matching the
/// layer under test (structure rule 6), so Content.Tests cannot reference
/// AcDream.Bake just to borrow its copy. Plain dat-access glue, not an
/// AC-specific algorithm.
///
internal sealed class ContentTestDatCollectionAdapter : IDatReaderWriter {
private readonly DatCollection _dats;
private readonly TestDatDatabaseWrapper _portal;
private readonly TestDatDatabaseWrapper _cell;
private readonly TestDatDatabaseWrapper _highRes;
private readonly TestDatDatabaseWrapper _language;
private readonly ReadOnlyDictionary _cellRegions;
public ContentTestDatCollectionAdapter(DatCollection dats) {
ArgumentNullException.ThrowIfNull(dats);
_dats = dats;
_portal = new TestDatDatabaseWrapper(dats.Portal);
_cell = new TestDatDatabaseWrapper(dats.Cell);
_highRes = new TestDatDatabaseWrapper(dats.HighRes);
_language = new TestDatDatabaseWrapper(dats.Local);
var regions = new Dictionary { [0u] = _cell };
_cellRegions = new ReadOnlyDictionary(regions);
}
public string SourceDirectory => _dats.Options.DatDirectory ?? string.Empty;
public IDatDatabase Portal => _portal;
public ReadOnlyDictionary CellRegions => _cellRegions;
public IDatDatabase HighRes => _highRes;
public IDatDatabase Language => _language;
public ReadOnlyDictionary RegionFileMap =>
new ReadOnlyDictionary(new Dictionary());
public int PortalIteration => _portal.Iteration;
public int CellIteration => _cell.Iteration;
public int HighResIteration => _highRes.Iteration;
public int LanguageIteration => _language.Iteration;
public bool TryGetFileBytes(uint regionId, uint fileId, ref byte[] bytes, out int bytesRead) {
return _dats.Cell.TryGetFileBytes(fileId, ref bytes, out bytesRead);
}
public IEnumerable ResolveId(uint id) {
var results = new List();
void CheckDb(TestDatDatabaseWrapper wrapper) {
var rawDb = wrapper.RawDatabase;
if (rawDb.Tree.TryGetFile(id, out _)) {
var type = rawDb.TypeFromId(id);
if (type != DBObjType.Unknown) {
results.Add(new IDatReaderWriter.IdResolution(wrapper, type));
}
}
}
CheckDb(_highRes);
CheckDb(_portal);
CheckDb(_language);
CheckDb(_cell);
return results;
}
public bool TrySave(T obj, int iteration = 0) where T : IDBObj =>
throw new NotSupportedException($"{nameof(ContentTestDatCollectionAdapter)} is read-only.");
public bool TrySave(uint regionId, T obj, int iteration = 0) where T : IDBObj =>
throw new NotSupportedException($"{nameof(ContentTestDatCollectionAdapter)} is read-only.");
public void Dispose() {
// The underlying DatCollection is owned by the caller.
}
}
internal sealed class TestDatDatabaseWrapper : IDatDatabase {
private readonly DatDatabase _db;
private readonly ConcurrentDictionary<(Type, uint), IDBObj> _cache = new();
private readonly object _lock = new();
public TestDatDatabaseWrapper(DatDatabase db) {
ArgumentNullException.ThrowIfNull(db);
_db = db;
}
internal DatDatabase RawDatabase => _db;
public DatDatabase Db => _db;
public int Iteration => _db.Iteration?.CurrentIteration ?? 0;
public IEnumerable GetAllIdsOfType() where T : IDBObj => _db.GetAllIdsOfType();
public bool TryGet(uint fileId, [MaybeNullWhen(false)] out T value) where T : IDBObj {
if (_cache.TryGetValue((typeof(T), fileId), out var cached)) {
value = (T)cached;
return true;
}
lock (_lock) {
if (_db.TryGet(fileId, out value)) {
_cache.TryAdd((typeof(T), fileId), value);
return true;
}
}
return false;
}
public bool TryGetFileBytes(uint fileId, [MaybeNullWhen(false)] out byte[] value) {
lock (_lock) {
return _db.TryGetFileBytes(fileId, out value);
}
}
public bool TryGetFileBytes(uint fileId, ref byte[] bytes, out int bytesRead) {
lock (_lock) {
return _db.TryGetFileBytes(fileId, ref bytes, out bytesRead);
}
}
public bool TrySave(T obj, int iteration = 0) where T : IDBObj =>
throw new NotSupportedException($"{nameof(TestDatDatabaseWrapper)} is read-only.");
public void Dispose() {
// The underlying DatDatabase is owned by DatCollection.
}
}