fix(spells): load complete retail DAT catalog

Replace the incomplete 3,956-row production CSV with one immutable projection of all 6,266 records in portal.dat. Preserve retail formula targeting, shared Spellbook/MagicRuntime metadata ownership, and fail startup when the required SpellTable is absent.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-15 21:17:13 +02:00
parent 09612f9981
commit 0eab7497c1
19 changed files with 633 additions and 114 deletions

View file

@ -23,7 +23,8 @@ public sealed class Spellbook
private readonly List<uint>[] _favoriteSpells = Enumerable.Range(0, 8)
.Select(_ => new List<uint>()).ToArray();
private readonly Dictionary<uint, uint> _desiredComponents = new();
private readonly SpellTable _table;
private SpellTable _table;
private bool _metadataInstalled;
private uint _spellbookFilters = 0x3FFFu;
/// <summary>
@ -37,6 +38,7 @@ public sealed class Spellbook
public Spellbook(SpellTable? table = null)
{
_table = table ?? SpellTable.Empty;
_metadataInstalled = table is not null;
}
/// <summary>
@ -51,6 +53,28 @@ public sealed class Spellbook
/// Returns <see cref="SpellTable.Empty"/> if none was provided.</summary>
public SpellTable Metadata => _table;
/// <summary>
/// Installs the production metadata table after DatCollection opens.
/// GameWindow constructs client state before Silk's OnLoad callback, while
/// portal.dat becomes available inside OnLoad. The table may be installed
/// once; replacing a populated catalog would invalidate active stacking and
/// presentation decisions.
/// </summary>
public void InstallMetadata(SpellTable table)
{
ArgumentNullException.ThrowIfNull(table);
if (_metadataInstalled)
{
if (ReferenceEquals(_table, table)) return;
throw new InvalidOperationException("Spell metadata is already installed.");
}
_table = table;
_metadataInstalled = true;
if (_learnedSpells.Count != 0) NotifySpellbookChanged();
if (_activeById.Count != 0) NotifyEnchantmentsChanged();
}
/// <summary>
/// Issue #6 — combined buff modifier for a vital stat. Aggregates
/// over <see cref="ActiveEnchantments"/> through