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
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.mapcustom_ej_creature.creature_id↔creature_template.entrycustom_ej_loot.item_id↔item_template.entrycustom_ej_creature.creature_display_idis optional and only used by the client's 3D portrait tab; pull it fromcreature_template.modelid1..modelid4when 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):
{
"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:
-- 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
- Edit data — INSERT/UPDATE rows in
custom_ej_*tables. - Validate —
.ej validate(no errors expected). - Export —
.ej export(writes JSON + Lua toExport.Path). - Ship — copy
EncounterJournalData.luainto the MoonWellClient EncounterJournal addon directory.
For loot, you can shortcut step 1:
- Insert the encounter and a
custom_ej_creaturerow withcreature_idset to the boss NPC id. - Run
.ej importloot— entries fromcreature_loot_template(and one level ofreference_loot_template) are inserted intocustom_ej_lootwithdifficulty_maskcopied from the creature card. Existing rows are skipped via the unique key. - Manually clean up: drop trash items, set
faction_mask/class_mask/sort_orderwhere needed. - Re-run
.ej validateand.ej export.
Validation
.ej validate verifies:
- every
tier_instance.tier_idandtier_instance.instance_idexists; - every
encounter.instance_idexists; - every
encounter.first_section_idexists or equals0; encounter.difficulty_maskonly uses bits valid for the parent instance type (dungeon →0x7, raid →0xF);- every
creature.encounter_idexists; - every
creature.creature_id(if non-zero) exists increature_template; - every
section.encounter_idexists; - every
section.parent_section_id/next_section_id/sub_section_id(if non-zero) exists; - every
loot.encounter_idexists; - every
loot.item_idexists initem_template; - no
lootduplicates 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:
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.