Your NPCs don't fight. They stand there and auto-attack because creature_template_spell (the database table that assigns spells to creatures) is empty and there's no SmartAI (TrinityCore's scripted behavior system) telling them what to cast. CreatureCodex fixes that.
Repository: github.com/VoxCore84/CreatureCodex
- Install the addon on any TrinityCore server — repacks included, no server patches needed
- Walk around and let creatures fight — the addon captures visible spell casts, channels, and auras in real time (server hooks add instant/hidden spells for 100% coverage)
- Open the export panel and hit the SmartAI tab — ready-to-apply SQL with estimated cooldowns, HP phase triggers, and target types
- Apply the SQL — your NPCs now cast spells with proper timing and behavior
CreatureCodex turns observation into working SmartAI. You watch mobs fight, it writes the smart_scripts and creature_template_spell inserts for you.
+-- Visual Scraper (client addon, works everywhere)
Walk near mobs -------------+-- Server Hooks (C++ UnitScript, 100% coverage)
+-- Ymir Integration (auto-merge from packet captures)
|
v
Browse in-game -> Export as SQL
+-- creature_template_spell (spell lists)
+-- smart_scripts (AI with cooldowns)
+-- new-only (just the gaps)
The SmartAI export isn't just a list of spell IDs — it uses the addon's timing intelligence to estimate cooldowns from observed cast intervals, detects HP-phase abilities (spells seen below 40% HP at least once get event_type=2 health triggers instead of timed repeats), and infers target types from cast-vs-aura ratios. It's a first draft you can tune, not a blank slate you have to build from scratch.
This data doesn't ship in DB2 files. It has to be observed from a live server. In 12.x, that got dramatically harder:
-
COMBAT_LOG_EVENT_UNFILTEREDis effectively dead. The combat log was the gold standard for capturing creature casts. In 12.x, cross-addon GUID tracking is severely locked down. Passive CLEU listening no longer gives reliable creature spell data. -
Taint and secret values. The 12.x engine injects opaque C++
userdatataints into spell IDs, GUIDs, and aura data. Standard Luatonumber()/tostring()silently fail on tainted values. Any addon touching spell data must wrap every access inpcallwithissecretvalue()checks or it breaks without warning. -
Instant casts are invisible.
UnitCastingInfo/UnitChannelInfoonly see spells with visible cast bars. Instant casts, triggered spells, and many boss mechanics never appear in these APIs — a significant portion of any creature's spell list is unobservable from the client. -
Traditional sniffing requires post-processing. The Ymir -> WowPacketParser pipeline produces the best data, but turning raw packet captures into usable spell lists has always meant offline parsing, manual review, and hand-written SQL.
CreatureCodex works around all of this. The client-side visual scraper polls cast bars at 10 Hz and scans nameplate auras at 5 Hz, wrapping every access in taint-safe helpers. This works on any server — repacks, custom builds, anything running a 12.x client.
For servers that can add C++ hooks, four UnitScript callbacks catch 100% of casts including instant and hidden ones, broadcast as lightweight addon messages. Both layers deduplicate automatically — zero gaps, zero noise.
And if you sniff with Ymir, CreatureCodex integrates directly — run the included tool on your WPP output, /reload, and the addon merges sniff data with scraper data automatically. Or skip the addon and generate SQL straight from your packet captures.
CreatureCodex has three data sources:
-
Client-side visual scraper (works everywhere, no server patches needed)
- Polls
UnitCastingInfo/UnitChannelInfoat 10 Hz for spell casts - Round-robin scans nameplates for auras at 5 Hz
- Records spell name, school, creature entry, and timestamps (HP% is available from server hooks only)
- Polls
-
Server-side sniffer (requires TrinityCore C++ hooks)
- Four
UnitScripthooks broadcast every creature spell event as addon messages - Catches 100% of casts including instant/hidden ones the client never sees
- Broadcasts only to nearby players (100 yd) who have CreatureCodex installed
- Four
-
Ymir integration (live merge from packet captures)
- Run Ymir alongside the game as usual — CreatureCodex works in parallel
- After WowPacketParser processes your
.pktfiles, run the included Python tool to convert the output - The addon auto-merges sniff data on
/reload— no need to exit the game - Catches instant casts, hidden spells, and triggered abilities the visual scraper can't see
- Also generates SQL directly from sniff data if you prefer to skip the addon entirely
When multiple sources run together, the addon deduplicates automatically — you get complete coverage with zero gaps.
| Spell Browser | Debug Mode |
|---|---|
![]() |
![]() |
Watch the demo video — walk through a zone, browse captured spells, export SmartAI SQL.
Go to the Releases page and pick one:
| Download | What it is | Who it's for |
|---|---|---|
CreatureCodex_Setup.exe |
GUI installer — walks you through setup step by step | Most people. It asks where your WoW and server are, then copies the right files to the right places. |
CreatureCodex-v1.0.0.zip |
Full package — everything in one folder | Developers who want to browse the source, or anyone who prefers to copy files manually. |
Which should I pick? If you're not sure, download
CreatureCodex_Setup.exe. It handles addon placement, sniff tool setup, and server script installation with a 3-step wizard. You can always grab the ZIP later if you need the raw files.
The installer has three modes:
- Addon Only — just the WoW addon, no server changes needed
- Addon + Sniff Tools — addon plus Ymir/WPP pipeline for packet capture analysis
- Full Source — everything above plus C++ server scripts and SQL for 100% spell coverage
Client-Only Install (No Server Patches) — click to expand
If you just want the visual scraper without modifying your server:
- Copy the
CreatureCodex/addon folder into your WoW installation's addon directory:For example:<WoW Install>/Interface/AddOns/CreatureCodex/C:\WoW\_retail_\Interface\AddOns\CreatureCodex\. Create theAddOnsfolder if it doesn't exist. - The folder should contain:
CreatureCodex.toc,CreatureCodex.lua,Export.lua,UI.lua,Minimap.lua, and theLibs/folder. - Log in. The addon registers automatically via the minimap button (gold book icon).
- Walk near creatures and observe them fighting — spells are captured in real time.
- Type
/ccin chat to open the browser panel and confirm the addon is working.
What you get: Visible casts and channels (anything the WoW API can detect). What you miss: Instant casts, hidden spells, and auras applied without visible cast bars.
Tip: If the addon doesn't appear in your addon list, check Game Menu -> AddOns -> enable "Load out of date AddOns" at the top. This is needed when the client version is newer than the addon's TOC Interface version.
Full Install (Server + Client) — click to expand
- TrinityCore
masterbranch (12.x / The War Within) - C++20 compiler (MSVC 2022+, GCC 13+, Clang 16+)
- Eluna Lua Engine (optional, for spell list queries and aggregation)
These four virtual methods must be added to UnitScript in your ScriptMgr. If you already have custom hooks, just add these to the existing class.
src/server/game/Scripting/ScriptMgr.h — Add to class UnitScript:
// CreatureCodex hooks
virtual void OnCreatureSpellCast(Creature* /*creature*/, SpellInfo const* /*spell*/) {}
virtual void OnCreatureSpellStart(Creature* /*creature*/, SpellInfo const* /*spell*/) {}
virtual void OnCreatureChannelFinished(Creature* /*creature*/, SpellInfo const* /*spell*/) {}
virtual void OnAuraApply(Unit* /*target*/, AuraApplication* /*aurApp*/) {}src/server/game/Scripting/ScriptMgr.cpp — Add the FOREACH_SCRIPT dispatchers:
void ScriptMgr::OnCreatureSpellCast(Creature* creature, SpellInfo const* spell)
{
FOREACH_SCRIPT(UnitScript)->OnCreatureSpellCast(creature, spell);
}
void ScriptMgr::OnCreatureSpellStart(Creature* creature, SpellInfo const* spell)
{
FOREACH_SCRIPT(UnitScript)->OnCreatureSpellStart(creature, spell);
}
void ScriptMgr::OnCreatureChannelFinished(Creature* creature, SpellInfo const* spell)
{
FOREACH_SCRIPT(UnitScript)->OnCreatureChannelFinished(creature, spell);
}
void ScriptMgr::OnAuraApply(Unit* target, AuraApplication* aurApp)
{
FOREACH_SCRIPT(UnitScript)->OnAuraApply(target, aurApp);
}src/server/game/Scripting/ScriptMgr.h — Also add these declarations to class ScriptMgr (a different class in the same file — search for class TC_GAME_API ScriptMgr):
void OnCreatureSpellCast(Creature* creature, SpellInfo const* spell);
void OnCreatureSpellStart(Creature* creature, SpellInfo const* spell);
void OnCreatureChannelFinished(Creature* creature, SpellInfo const* spell);
void OnAuraApply(Unit* target, AuraApplication* aurApp);Four one-liner hooks are added inside existing if (Creature* caster = ...) blocks in Spell.cpp and at the end of Unit::_ApplyAura() in Unit.cpp.
See server/HOOKS.md for the exact code, variable names, and insertion points. The auto-patcher (install_hooks.py) applies these automatically — use HOOKS.md only if you prefer to patch by hand.
The sniffer checks if a player has the CCDX addon prefix registered before sending them data. Add this small helper to WorldSession (it reads the _registeredAddonPrefixes member that already exists in the class):
src/server/game/Server/WorldSession.h — Add to the public: section of class WorldSession:
bool IsAddonRegistered(std::string_view prefix) const;src/server/game/Server/WorldSession.cpp:
bool WorldSession::IsAddonRegistered(std::string_view prefix) const
{
for (auto const& p : _registeredAddonPrefixes)
if (p == prefix)
return true;
return false;
}src/server/game/Accounts/RBAC.h — Add to the permission enum:
RBAC_PERM_COMMAND_CREATURE_CODEX = 3012,Then apply sql/auth_rbac_creature_codex.sql to your auth database, or run manually:
INSERT IGNORE INTO `rbac_permissions` (`id`, `name`) VALUES (3012, 'Command: codex');
-- Link to GM role (role 193 = GM commands)
INSERT IGNORE INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES (193, 3012);-
Copy
server/creature_codex_sniffer.cppandserver/cs_creature_codex.cppto yoursrc/server/scripts/Custom/directory. -
Register them in
custom_script_loader.cpp:void AddSC_creature_codex_sniffer(); void AddSC_creature_codex_commands(); void AddCustomScripts() { // ... your existing scripts ... AddSC_creature_codex_sniffer(); AddSC_creature_codex_commands(); }
If you use Eluna, copy server/lua_scripts/creature_codex_server.lua to your Eluna scripts directory (default: lua_scripts/ next to your worldserver binary). This adds:
- Spell list queries: Addon can request the full spell list for any creature from
creature_template_spell - Creature info: Name, faction, level range, classification
- Zone completeness: Query all creatures in a map with their known spell counts
- Multi-player aggregation: Players can submit discoveries to a shared server-side table
For aggregation, create the shared table by running the following SQL against whichever database you want it in (default: characters):
CREATE TABLE IF NOT EXISTS `codex_aggregated` (
`creature_entry` INT UNSIGNED NOT NULL,
`spell_id` INT UNSIGNED NOT NULL,
`cast_count` INT UNSIGNED NOT NULL DEFAULT 1,
`last_reporter` VARCHAR(64) NOT NULL DEFAULT '',
`last_seen` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`creature_entry`, `spell_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;This table must exist in your characters database (the same one that CharDBExecute targets).
- Copy the
CreatureCodex/addon folder contents toInterface\AddOns\CreatureCodex\. - Rebuild your server. From your build directory:
# CMake + Make (Linux) cmake --build . --config RelWithDebInfo -j $(nproc) # CMake + Ninja ninja -j$(nproc) # Visual Studio (Windows) # Open the .sln and build in Release or RelWithDebInfo
Ymir Integration (Sniff Users) — click to expand
If you sniff with Ymir, CreatureCodex works alongside it. The addon captures what the client can see in real time (~80% of spells), and a background companion automatically feeds WowPacketParser data into the addon to fill in the rest — instant casts, hidden spells, triggered abilities. Everything merges inside the game. You never exit.
- Install the addon normally (see Client-Only Install above)
- Start the background watcher alongside Ymir:
It auto-detects your WoW install and SavedVariables folder. If auto-detection fails, point it manually:
python tools/wpp_watcher.py
python tools/wpp_watcher.py --wow-dir "C:/WoW/_retail_" --watch-dir "C:/sniffs"
- Play normally with Ymir + watcher running in the background
- The addon captures visible casts and auras in real time via the visual scraper
- The watcher processes your WPP output automatically as files appear — no manual steps
- Type
/cc syncto reload the UI and import the new data - The addon reports what it imported:
[CreatureCodex] Imported sniff data: +142 creatures, +891 spells from WPP. - Browse and export with
/cc— your data now includes both scraper observations and packet-confirmed spells
That's it. The visual scraper gives you spell names and real-time browsing. The sniff data fills in instant casts, server-side triggers, and hidden auras the client can't see. The addon deduplicates everything — together they're better than either alone.
- Python 3.10+
- GitHub CLI (
gh) authenticated — install from cli.github.com - curl (included by default on Windows 10+)
- WowPacketParser (produces
.txtoutput from Ymir.pktcaptures)
If you don't need to browse in-game and just want SQL from your sniff data:
# creature_template_spell SQL (default)
python tools/wpp_import.py sniff1.txt sniff2.txt
# -> creature_template_spell.sql
# SmartAI stubs with estimated cooldowns
python tools/wpp_import.py --smartai sniff1.txt
# -> smart_scripts.sql
# Both at once
python tools/wpp_import.py --sql --smartai sniff1.txt
# Apply directly
mysql -u root -p world < creature_template_spell.sqlThe script parses SMSG_SPELL_GO, SMSG_SPELL_START, and SMSG_AURA_UPDATE opcodes. It estimates cooldowns from observed cast intervals and infers target types from cast-vs-aura ratios — the same intelligence the addon uses.
| Flag | Output File | Contents |
|---|---|---|
--sql (default) |
creature_template_spell.sql |
DELETE + INSERT pairs for spell lists |
--smartai |
smart_scripts.sql |
SmartAI stubs with cooldown estimates |
--addon |
CreatureCodexWPP.lua |
Auto-merge into addon on /reload |
--lua |
CreatureCodexDB.lua |
Full SavedVariables replacement |
Use -o to override the output filename (single format only). Flags combine: --sql --smartai generates both SQL files in one pass.
- Walking produces denser data than flying. When sniffing, walk through areas on foot for better creature spell coverage.
- Multiple sniffs merge cleanly. Pass multiple
.txtfiles to combine data from different sessions. - Scraper + sniff = complete picture. The visual scraper gives you spell names and real-time browsing; the sniff data gives you spell IDs and full coverage. Together they're better than either alone.
| Command | Description |
|---|---|
/cc or /codex |
Toggle the browser panel |
/cc export |
Open the export panel |
/cc debug |
Toggle debug output in chat |
/cc stats |
Print capture statistics |
/cc zone |
Request zone creature data from server (requires Eluna) |
/cc submit |
Submit aggregated data to server (requires Eluna) |
/cc sync |
Reload UI to import WPP sniff data (run wpp_import.py --addon first) |
/cc reset |
Clear all stored data (with confirmation) |
These commands require the server-side sniffer from the Full Install. They won't exist on your server unless you've added the C++ scripts and RBAC permission from Step 4.
| Command | Description |
|---|---|
.codex query <entry> |
Show all spells for a creature entry |
.codex stats |
Show sniffer statistics (online players, addon users, blacklist size) |
.codex blacklist add <spellId> |
Add a spell to the runtime broadcast blacklist |
.codex blacklist remove <spellId> |
Remove a spell from the blacklist |
.codex blacklist list |
Show all runtime-blacklisted spells |
The export panel offers four tabs:
- Raw — Machine-readable format:
entry:name|spellId:totalCount:school:spellName|...(one creature per line, prefixed withCCEXPORT:v3) - SQL —
INSERT INTO creature_template_spellstatements ready to apply - SmartAI —
INSERT INTO smart_scriptsfor AI-driven casting - New Only — Same as SQL but filters to spells not already in
creature_template_spell
WARNING — Destructive Operation: The SQL export uses
DELETE FROM creature_template_spell WHERE CreatureID = <entry>and the SmartAI export usesDELETE FROM smart_scripts WHERE entryorguid = <entry> AND source_type = 0before inserting. This removes all existing spells/scripts for that creature and replaces them with what CreatureCodex observed. If you have hand-tuned data, back it up first or use the New Only tab, which usesINSERT IGNOREand never deletes.
After exporting from the addon, you have SQL text ready to run against your world database. Here are three common ways to apply it:
- HeidiSQL (Windows): Connect to your DB, select the
worlddatabase, open a new Query tab, paste the SQL, and hit Execute (F9). - phpMyAdmin (web): Select the
worlddatabase, go to the SQL tab, paste, and click Go. - MySQL CLI:
Or paste directly into an interactive
mysql -u root -p world < exported_spells.sqlmysqlsession after runningUSE world;.
The SQL and SmartAI exports include DELETE + INSERT pairs so they're safe to re-run — they won't create duplicates.
Left-click opens the browser. Right-click opens export. The minimap button can be dragged to reposition.
The addon and server communicate over the CCDX addon message prefix using pipe-delimited messages:
| Direction | Code | Format | Purpose |
|---|---|---|---|
| S->C | SC |
SC|entry|spellID|school|name|hp% |
Spell cast complete |
| S->C | SS |
SS|entry|spellID|school|name|hp% |
Spell cast started |
| S->C | CF |
CF|entry|spellID|school|name|hp% |
Channel finished |
| S->C | AA |
AA|entry|spellID|school|name|hp% |
Aura applied |
| C->S | SL |
SL|entry |
Request spell list |
| C->S | CI |
CI|entry |
Request creature info |
| C->S | ZC |
ZC|mapId |
Request zone creatures |
| C->S | AG |
AG|entry|spellId:count,... |
Submit aggregated data |
| S->C | AR |
AR|entry|OK |
Aggregation acknowledgement |
CreatureCodex/
CreatureCodex/ -- ADDON FOLDER (copy to Interface/AddOns/CreatureCodex/)
CreatureCodex.toc -- Addon TOC
CreatureCodex.lua -- Core engine (capture + DB)
Export.lua -- 4-tab export panel
UI.lua -- Browser panel
Minimap.lua -- LibDBIcon minimap button
Libs/ -- LibStub, CallbackHandler, LibDataBroker, LibDBIcon
server/
creature_codex_sniffer.cpp -- C++ UnitScript hooks (broadcast layer)
cs_creature_codex.cpp -- .codex GM command tree
install_hooks.py -- Auto-patcher for TC source hooks
HOOKS.md -- Manual patching reference
lua_scripts/
creature_codex_server.lua -- Eluna handlers (spell lists, aggregation)
tools/
wpp_import.py -- WPP -> SQL / addon import tool
wpp_watcher.py -- Background companion for auto-import
_README.txt -- Tools folder overview
parsed/
_What_To_Do_With_These_Files.txt -- Guide for parsed output
_GUIDE/
01_Quick_Start.md -- Get running in 2 minutes
02_Server_Setup.md -- Server hooks + C++ setup
03_Retail_Sniffing.md -- Ymir + WPP pipeline
04_Understanding_Exports.md -- Export formats explained
session.py -- Session manager (Ymir lifecycle + SV backup)
update_tools.py -- Tool downloader (requires gh CLI)
Start Ymir.bat -- Launch Ymir + session manager (Windows)
Update Tools.bat -- Download/update WPP and Ymir (Windows)
Parse Captures.bat -- Run WPP on existing .pkt files (Windows)
start_ymir.sh -- Launch Ymir + session manager (Linux/macOS)
update_tools.sh -- Download/update WPP and Ymir (Linux/macOS)
parse_captures.sh -- Run WPP on existing .pkt files (Linux/macOS)
README.md -- This file
README_RU.md -- Russian translation
README_DE.md -- German translation
LICENSE -- MIT
MIT. Libraries in Libs/ retain their original licenses.

