Files
moonwell-core/modules/mod-encounter-journal/README.md
T

196 lines
8.8 KiB
Markdown

# 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 |
| ---------------- | ---------------------------------------------------------------------------- |
| 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 importskeleton` | Generate instance/encounter/creature/section rows from `instance_template` + `instance_encounters`. |
| `.ej importloot` | Auto-populate `custom_ej_loot` from `creature_loot_template` (skips dupes). |
| `.ej importall` | Run `importskeleton` then `importloot` back-to-back. |
| `.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.