Skip to content

Package Deltas cannot yet reach DBC catalogues outside the spell stream #313

Open

Description

@Mathih13

Expected. A Package author should be able to tune non-spell DBC-backed catalogues (factions, auction house rates, talents, skill-ability thresholds, and similar tables) through the same typed Package Delta pipeline the spell family already uses, with identifiers and references checked before any write.

Actual (at 87109e3c). Only the spell family has a Package Delta path today: casts, creature_ai, creatures, fixtures, gameobjects, globals, gossip, items, loot, quest, script, spellmeta, spell and trainers all live under module/src/package_import/, with no talents or catalogues family. The two DBC-loading importer runs, run (importer/src/dbc.rs#L167) and run_talents (importer/src/talent.rs#L141), do not stamp game_import_meta, so neither has a base-import owner a Package claim could replay against.

A proposal on this issue inventories every DBC-backed table outside the spell stream and names a v1 set: two update-only families, talents and catalogues, six claimable tables, and no Package Identifier Range, since every candidate table is mirrored by the client's own DBC and an inserted row would be unreachable. It also raises five open questions: whether an update-only v1 with no insert band is the right scope, what to do about game_skill_ability's positional (non-portable) primary key, whether the whole --dbc run should be one family or several, whether lyracore packages replay should grow a DBC path in the same change, and how a claim should check a spell reference against a family that lands in a separate base import.

Fix direction. A maintainer answers the five open questions on this issue; the proposed v1 set is the contract to build once they do.

Activity

  1. added
    enhancementNew feature or request
    P3someday / nice-to-have
    ready-for-agentComplete enough to build from the issue alone, by a person or their agent
    on Aug 24, 2026
  2. Mathih13 commented on Sep 2, 2026

    @Mathih13
    ContributorAuthor

    This is an agent's proposal for the v1 Package-editable DBC set, awaiting maintainer approval on this issue before any implementation.

    Inventory of DBC catalogues outside the spell stream

    Two importer invocations load them. --dbc <Data> alone runs importer/src/dbc.rs::run and clears and reloads 16 tables in one pass. --dbc <Data> --talents runs importer/src/talent.rs and clears and reloads 2 more. Neither invocation stamps game_import_meta, so no table below has a base-import owner today. --family covers the --dump ETL only.

    No table below is map-filtered. Each loads all its rows, so all are global catalogues, not World Import Scope. import-world.sh runs both invocations once per target database, so every World Shard and the Instance Pool holds a full copy. Realm-core holds accounts and no game catalogue.

    Table Source DBC Run Primary key Key stable across clients Read by
    game_faction_template FactionTemplate.dbc --dbc id u32 yes hostility (faction.rs), auctioneer resolution, game_race_info.faction_template
    game_faction Faction.dbc --dbc faction_id u32 yes SMSG_INITIALIZE_FACTIONS, reputation
    game_auction_house AuctionHouse.dbc --dbc id u32 yes auction deposit and consignment cut
    game_char_base_info CharBaseInfo.dbc --dbc race_class u16 yes create_character combo gate
    game_race_info ChrRaces.dbc --dbc race u8 yes login display model, nameplate faction
    game_start_item CharStartOutfit.dbc --dbc id u64 positional no grant_starter_item
    game_skill_line SkillLine.dbc --dbc skill_line u32 yes profession tier-cap parity guard (~135 rows)
    game_skill_ability SkillLineAbility.dbc --dbc id u64 positional no recipe skill-up band, autolearn threshold (~9-10k rows)
    game_skill_availability SkillRaceClassInfo.dbc --dbc id u64 positional no weapon-master availability, not wired (~700-800 rows)
    game_area AreaTable.dbc --dbc id u32 yes rest-state naming, exploration XP, terrain::zone_id_at
    game_area_trigger AreaTrigger.dbc --dbc id u32 yes inn triggers, dungeon portals, explore objectives
    game_graveyard WorldSafeLocs.dbc --dbc id u32 yes corpse release, via game_graveyard_zone from the globals dump family
    game_creature_family CreatureFamily.dbc --dbc family_id u32 yes pet food and tameable gates, not wired (188 rows)
    game_lock Lock.dbc --dbc id u64 positional no gameobject open gate, via by_lock
    game_taxi_node TaxiNodes.dbc --dbc id u32 yes flight, plus a unique client_node_id inside the client taxi mask
    game_taxi_path TaxiPath.dbc --dbc id u32 yes flight route and fare
    game_taxi_path_node TaxiPathNode.dbc --dbc id u32 yes flight geometry
    game_talent_tab TalentTab.dbc --dbc --talents tab_id u32 yes talent panes (27 rows)
    game_talent Talent.dbc --dbc --talents talent_id u32 yes learn_talent, apply_learned_talents (432 rows)

    "Positional" means the importer writes a 1-based counter over DBC record order, not the DBC's own id. A claim keyed on such an id is not portable between operators, because a different patch chain shifts every row. game_quest_objective shows the way out: it has an auto_inc storage key and its claims use the logical key (quest_entry, obj_index).

    Proposed v1 set

    One rule decides the whole set. Every catalogue here is mirrored by the client's own DBC, so a row a Package invents is unreachable or invisible on an unmodified client. v1 is therefore update-only. No table accepts an insert, no family owns a Package Identifier Range, and clear_package_range is a no-op. That removes the largest part of what the casts and trainers families cost. DeltaError::InsertNotSupported already exists for exactly this, from game_creature_cast.

    Two Import Families, one per invocation that already exists. A family is the unit a base import clears, and the standalone --dbc run clears its 16 tables together, so it is one family. This follows the globals precedent in the --dump ETL.

    Family Base-import owner Shard routing Claimable table Claimable columns Referential checks
    talents --dbc <Data> --talents every Shard the world import targets game_talent name, tier, column, max_rank, spell_id, grant_spell_id, rank_spell_2..5, required_talent_id, required_talent_rank, required_points_in_tree, required_spell_id every spell id is 0 or a game_spell row; required_talent_id is 0 or a game_talent row after the family lands; max_rank in 1..=5 and consistent with the rank_spell_* set
    talents same same game_talent_tab name, class_mask, race_mask class_mask is one-hot
    catalogues --dbc <Data> every Shard the world import targets game_faction_template faction_group, friend_group, enemy_group, enemy_0..3, friend_0..3 every named faction is 0 or a game_faction row
    catalogues same same game_faction base_standing none
    catalogues same same game_skill_ability min_skill, acquire_method, gray, green green <= gray
    catalogues same same game_auction_house deposit_rate, consignment_rate, name both rates in 0..=100, the bound auction_house_sql already enforces

    tree_id and tab_id on game_talent, order_index on game_talent_tab, reputation_index on game_faction, faction on game_faction_template, and spell_id/skill_line on game_skill_ability stay out of the claimable set. Each one is the client's own view of the row. Changing it server-side desynchronizes the two halves and shows nothing to a player.

    Two acceptance criteria need no new work. Table::parse is a closed catalogue, so an unsupported DBC table already fails with a refusal that names every claimable table. The licensing firewall in dbc.rs and pack_client.rs already refuses a committed .dbc, and a claim is a typed row artifact.

    Size, against commit 94d5cb8 (2 families, 3 tables, 1,834 lines over 18 files, with bands, clear passes and inserts):

    Piece Size vs 94d5cb8 Note
    lyracore-package-delta schema, keys, tests about the same 6 tables against 3, but no band and no insert path
    module/src/package_import/{talents,catalogues}.rs about 0.8x setters and update_target only, no clear_package_range body
    importer wiring new, about 100 lines two stamp_family calls, two run_package_stage calls, extend the --packages gate to --dbc and --dbc --talents. casts and trainers got this free because their --dump families already existed
    lyracore-cli packages replay new, about 150 lines see open question 4

    Excluded from v1:

    Excluded Why
    game_taxi_node, game_taxi_path, game_taxi_path_node the importer validates the three as one graph and refuses a malformed catalogue. A claim would have to repeat that validation inside the reducer. Node ids are also bounded by the client 256-bit taxi mask. High cost, low modder value
    game_area zone and subzone names come from the client's own AreaTable.dbc. A server-side rename shows nowhere
    game_area_trigger the client sends only trigger ids its own AreaTrigger.dbc holds. Moving a volume server-side splits the two views
    game_graveyard the point comes from WorldSafeLocs.dbc and its zone link comes from the globals dump family. The two halves would sit in different families. Revisit when globals gets a schema
    game_char_base_info, game_race_info character creation is gated by the client UI first. A combo the client will not offer is unreachable
    game_start_item, game_lock, game_skill_availability positional primary key, and each needs a logical key before a claim is portable. game_lock is also only half a story: the other half is game_gameobject_template.lock_id in the gameobjects dump family
    game_skill_line, game_creature_family names and groupings are client-drawn, and the pet food and tameable gates are not wired. A claim would change nothing today
    Spell.dbc headers and effects, DBC binaries, terrain, navigation, vmap, models out of scope by this issue

    Open questions

    1. Update-only v1, no Package Identifier Range. talents and catalogues would be the first families with no band, so clear_package_range is a no-op for both. Recommendation: accept it. Every catalogue here is client-mirrored, so an invented row is unreachable. Give a table a band later, one table at a time, when it earns one.
    2. game_skill_ability primary key. skill_ability_sql writes a positional counter, so its ids move when the operator's patch chain changes, and a claim keyed on one is not portable. Recommendation: in the same change, write the DBC's own row id instead, with a duplicate guard. If you prefer not to touch that importer path, drop game_skill_ability and the catalogues family carries three tables.
    3. Family granularity. The standalone --dbc run clears 16 tables in one invocation, so it is one clear-and-reload unit. Recommendation: one family named catalogues. The alternative is a --family selector for the --dbc path, which is more importer work and buys nothing until a second DBC family exists.
    4. lyracore packages replay reimports Spell.dbc only. A DBC family needs it to run --dbc and --dbc --talents too. Recommendation: extend replay_command in the CLI repo in the same change. Note the same gap already stops the items, quests, loot, casts and trainers families from replaying, because replay reimports the spell family alone. That gap deserves its own issue.
    5. Cross-family references. A talent may point at a Package Spell, and the spell family and the talents family are separate base imports with no ordering rule between them. Recommendation: check spell_id against game_spell as the Shard holds it at apply time, the rule trainers already uses, and document that a Package replays the spell family first.

    Proposed by Claude (model claude-opus-5) via Claude Code subagent.

  3. added
    ready-for-humanNeeds a maintainer: a decision, a maintainer's Realm, or coordination
    and removed
    ready-for-agentComplete enough to build from the issue alone, by a person or their agent
    on Oct 8, 2026
  4. changed the title [-]Package Deltas: support non-spell DBC catalogues[/-] [+]Package Deltas cannot yet reach DBC catalogues outside the spell stream[/+] on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3someday / nice-to-haveenhancementNew feature or requestready-for-humanNeeds a maintainer: a decision, a maintainer's Realm, or coordination

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions