using AcDream.Content;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Audio;
///
/// Resolves the DID of retail's interface sound bank by walking the dats, the
/// way retail does, instead of carrying a literal.
///
///
/// ClientUISystem::GetUISoundTable @ 0x00563FB0 calls
/// DBObj::GetByEnum @ 0x00415490, and
/// DBCache::GetDIDFromEnum @ 0x00413940 resolves the answer with
/// two EnumIDMap hops off m_MasterMapID: keyed first by the enum
/// INDEX (7 for the UI bank), then by the type key. Same chain and same helper
/// shape as and the
/// portal tunnel's setup/animation lookup — the master id comes from the portal
/// dat header rather than being searched for.
///
///
///
/// Against the shipped dats this resolves to 0x2000004B, a table holding
/// exactly the 32 UI_* slots.
/// UiSoundTableResolutionTests pins the walk, the DID, and the content.
///
///
public static class UiSoundTableResolver
{
/// The enum index the UI sound bank lives at.
public const uint UiSoundTableEnumSlot = 7u;
///
/// The type key the second hop uses. GetByEnum(type, idx, cache) hands
/// (type, idx) to the enum chain and the resolved DID to
/// DBCache::Get(did, cache); a SoundTable's CACHE type is 0x22
/// (CLOCache(cache, CSoundTable::Allocator, 0x22)), which is not this
/// key. The lane-5 research note transposed the two arguments.
///
public const uint UiSoundTableTypeKey = 0x10000003u;
///
/// Resolve the bank's DID, or 0 when the dats carry no such chain (in which
/// case interface sounds stay silent rather than playing a guessed table).
///
public static uint Resolve(IDatReaderWriter dats)
{
if (dats is null)
return 0u;
uint masterDid = (uint)dats.Portal.Db.Header.MasterMapId;
if (masterDid == 0)
return 0u;
if (!dats.Portal.TryGet(masterDid, out var master) || master is null)
return 0u;
if (!master.ClientEnumToID.TryGetValue(UiSoundTableEnumSlot, out uint perSlotDid)
|| perSlotDid == 0)
{
return 0u;
}
if (!dats.Portal.TryGet(perSlotDid, out var perSlot) || perSlot is null)
return 0u;
return perSlot.ClientEnumToID.TryGetValue(UiSoundTableTypeKey, out uint did) ? did : 0u;
}
}