using AcDream.App.UI;
using DatReaderWriter;
using AcDream.Content;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Rendering;
/// Resolves retail global cursor enum IDs through the portal EnumIDMap chain.
internal sealed class RetailCursorResolver
{
private readonly IDatReaderWriter _dats;
private readonly object _datLock;
private readonly Dictionary _didByEnum = new();
private readonly HashSet _missingEnums = new();
public RetailCursorResolver(IDatReaderWriter dats, object datLock)
{
_dats = dats;
_datLock = datLock;
}
public bool TryResolve(RetailGlobalCursorKind kind, out UiCursorMedia cursor)
{
cursor = default;
if (!RetailCursorCatalog.TryGetGlobalCursor(kind, out var spec))
return false;
return TryResolve(spec, out cursor);
}
internal bool TryResolve(RetailCursorSpec spec, out UiCursorMedia cursor)
{
cursor = default;
if (!spec.IsValid)
return false;
if (_didByEnum.TryGetValue(spec.EnumId, out uint cachedDid))
{
cursor = new UiCursorMedia(cachedDid, spec.HotspotX, spec.HotspotY);
return true;
}
if (_missingEnums.Contains(spec.EnumId))
return false;
uint did = ResolveDidByEnum(spec.EnumId);
if (did == 0)
{
_missingEnums.Add(spec.EnumId);
return false;
}
cursor = new UiCursorMedia(did, spec.HotspotX, spec.HotspotY);
_didByEnum[spec.EnumId] = did;
return true;
}
private uint ResolveDidByEnum(uint cursorEnum)
{
lock (_datLock)
{
uint masterDid = (uint)_dats.Portal.Db.Header.MasterMapId;
if (masterDid == 0)
return 0;
if (!_dats.Portal.TryGet(masterDid, out var master) || master is null)
return 0;
if (!master.ClientEnumToID.TryGetValue(RetailCursorCatalog.CursorEnumTable, out uint cursorMapDid))
return 0;
if (!_dats.Portal.TryGet(cursorMapDid, out var cursorMap) || cursorMap is null)
return 0;
return cursorMap.ClientEnumToID.TryGetValue(cursorEnum, out uint did) ? did : 0;
}
}
}