# mod-encounter-journal Source-of-truth for the **MoonWellClient EncounterJournal** addon. Stores all data (tiers, instances, encounters, sections, creatures, loot) in `acore_world` under `custom_ej_*` tables and exports them as JSON / Lua that the client can consume directly. No DBC dependency. ## Layout ```text mod-encounter-journal/ ├── conf/ module configuration ├── data/sql/db-world/base/ │ ├── 01_encounter_journal_schema.sql table definitions │ └── 02_encounter_journal_sample.sql sample data (Deadmines, Naxxramas) ├── data/sql/db-world/updates/ future incremental migrations ├── docs/encounter_journal_format.md output structure reference ├── src/ C++ implementation (manager + commands) └── tools/json_to_lua.py offline JSON → Lua fallback ``` ## Tables | Table | Purpose | | --------------------------- | ---------------------------------------------------------- | | `custom_ej_tier` | Top-level expansion / content bucket | | `custom_ej_instance` | Dungeon / raid header | | `custom_ej_tier_instance` | N:M tier ↔ instance | | `custom_ej_encounter` | Boss / encounter under an instance | | `custom_ej_creature` | Creature card (portrait, name, description) per encounter | | `custom_ej_section` | Tree of Overview / Abilities sections | | `custom_ej_loot` | Explicit loot table per encounter | References to standard AzerothCore tables: - `custom_ej_instance.map_id` ↔ `instance_template.map` - `custom_ej_creature.creature_id` ↔ `creature_template.entry` - `custom_ej_loot.item_id` ↔ `item_template.entry` - `custom_ej_creature.creature_display_id` is optional and only used by the client's 3D portrait tab; pull it from `creature_template.modelid1..modelid4` when populating manually. ## Bitmasks ### `instance.flags` | Bit | Meaning | | ------- | ----------------- | | `0x000` | dungeon (default) | | `0x010` | raid | | `0x040` | hide difficulty | | `0x800` | open world | ### `encounter.difficulty_mask` For dungeons: | Bit | Meaning | | ----- | --------------- | | `0x1` | normal | | `0x2` | heroic | | `0x4` | mythic (custom) | For raids: | Bit | Meaning | | ----- | --------- | | `0x1` | 10 normal | | `0x2` | 25 normal | | `0x4` | 10 heroic | | `0x8` | 25 heroic | ### `section.flags` | Bit | Meaning | | ------ | ------------ | | `0x1` | starts open | | `0x2` | heroic only | ## Console / GM commands All commands require **administrator** rights, except `info` which is gamemaster-only. They run from the in-game chat **and** the worldserver console. | Command | What it does | | ---------------- | ---------------------------------------------------------------------------- | | `.ej info` | Print row counts of the in-memory cache. | | `.ej reload` | Re-read all `custom_ej_*` tables. | | `.ej validate` | Run integrity checks (see "Validation" below). | | `.ej importloot` | Auto-populate `custom_ej_loot` from `creature_loot_template` (skips dupes). | | `.ej export` | Write `EncounterJournalData.json` (and `.lua`) to the configured path. | ## Configuration `conf/mod_encounter_journal.conf.dist` (rename to `.conf` to override): | Option | Default | Description | | ----------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------- | | `EncounterJournal.Enable` | `1` | Master switch. | | `EncounterJournal.Export.Path` | (current working dir) | Output directory; must exist & be writable. | | `EncounterJournal.Export.JsonFile` | `EncounterJournalData.json` | JSON filename. | | `EncounterJournal.Export.LuaFile` | `EncounterJournalData.lua` | Lua filename. Empty string skips Lua generation. | | `EncounterJournal.Export.LuaGlobal` | `MoonWellEncounterJournalData` | Name of the Lua global the addon reads. | | `EncounterJournal.ExportOnStart` | `0` | When `1`, exports JSON/Lua right after startup load (useful for headless docker without TTY). | ## Output format The exporter writes the following top-level structure (full per-row layout in [`docs/encounter_journal_format.md`](docs/encounter_journal_format.md)): ```jsonc { "tiers": [ /* [id, name, flags, sort_order] */ ], "instances": { /* "instance_id": [...] */ }, "tierInstances": { /* "tier_id": [instance_id, ...] */ }, "encounters": { /* "instance_id": [[...], [...]] */ }, "creatures": { /* "encounter_id": [[...], [...]] */ }, "sections": { /* "section_id": [...] */ }, "items": { /* "encounter_id": [[...], [...]] */ } } ``` Field order inside each row matches the layout the MoonWellClient EncounterJournal addon expects, so the Lua file can be loaded directly: ```lua -- in your addon Init() or once on load local data = MoonWellEncounterJournalData for _, tier in ipairs(data.tiers) do -- tier[1]=id, tier[2]=name, tier[3]=flags, tier[4]=sort_order end ``` ## Workflow 1. **Edit data** — INSERT/UPDATE rows in `custom_ej_*` tables. 2. **Validate** — `.ej validate` (no errors expected). 3. **Export** — `.ej export` (writes JSON + Lua to `Export.Path`). 4. **Ship** — copy `EncounterJournalData.lua` into the MoonWellClient EncounterJournal addon directory. For loot, you can shortcut step 1: 1. Insert the encounter and a `custom_ej_creature` row with `creature_id` set to the boss NPC id. 2. Run `.ej importloot` — entries from `creature_loot_template` (and one level of `reference_loot_template`) are inserted into `custom_ej_loot` with `difficulty_mask` copied from the creature card. Existing rows are skipped via the unique key. 3. Manually clean up: drop trash items, set `faction_mask` / `class_mask` / `sort_order` where needed. 4. Re-run `.ej validate` and `.ej export`. ## Validation `.ej validate` verifies: - every `tier_instance.tier_id` and `tier_instance.instance_id` exists; - every `encounter.instance_id` exists; - every `encounter.first_section_id` exists or equals `0`; - `encounter.difficulty_mask` only uses bits valid for the parent instance type (dungeon → `0x7`, raid → `0xF`); - every `creature.encounter_id` exists; - every `creature.creature_id` (if non-zero) exists in `creature_template`; - every `section.encounter_id` exists; - every `section.parent_section_id` / `next_section_id` / `sub_section_id` (if non-zero) exists; - every `loot.encounter_id` exists; - every `loot.item_id` exists in `item_template`; - no `loot` duplicates by `(encounter_id, item_id, difficulty_mask, faction_mask, class_mask)`. `sort_order` stability is enforced by the schema (column has no `AUTO_INCREMENT`/random default, exporter sorts on it). ## Offline JSON → Lua If you produce the JSON outside the worldserver (e.g., from a CI job that talks to MySQL directly), use the bundled converter: ```sh python3 modules/mod-encounter-journal/tools/json_to_lua.py \ --input EncounterJournalData.json \ --output EncounterJournalData.lua \ --global MoonWellEncounterJournalData ``` The output uses the same field order, key sort, and global name as `.ej export`, so the addon does not care which path produced the file. Whitespace / float formatting may differ slightly.