Every claim below was checked against the tree before being changed, and the ones that still hold were left alone. `src/tools/Extractor_projects` was listed as a submodule. It is not one -- .gitmodules has exactly four entries (dep, src/realmd, src/modules/SD3, src/modules/Eluna, win), and src/CMakeLists.txt records that the submodule was removed and the in-tree baker replaced it. Anyone following the old line would look for a submodule that is not there and miss that src/tools/extractor/ is ordinary source. `BUILD_TOOLS=0`: the paragraph said the asset extractors "are not used". They are: src/CMakeLists.txt adds tools/extractor UNCONDITIONALLY, with the reason written in place -- the .tile files it bakes are what src/shared/terrain reads at runtime. The flag now only chooses whether the executable is built. The Movemap generator it named is gone too; navmesh generation is inside the extractor. The documented CI flags did not match the workflow. CI passes -DBUILD_TOOLS=1 (not 0) plus -DWITH_TESTS=1 -DWITH_NET_TESTS=0, and configures with Ninja via cmake -S/-B. The old block mattered more than a stale line usually does: read literally, it said extractor changes are not compiled by CI, when in fact every CI run builds them. Added, because both are deploy-time traps that cost real time when hit: the tile format version means a stale bake is refused outright, so the extractor must be rebuilt AND re-run; and the extractor is what writes the data.manifest that World::VerifyDataIntegrity reads, so a boot-time "unverified" notice means the bake predates the manifest rather than that something is broken. The `mkdir _build` invocation was replaced with an out-of-tree one, matching the standing rule that build artefacts never land in the working tree. Left alone deliberately: the architecture note naming Master::WorldLoop as the world heartbeat. That member still exists and still is the heartbeat -- the world/map tick split landed inside World and MapManager, not as a second loop in Master -- so the note is not stale, and rewriting it on the strength of a nearby change would be a guess. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7.1 KiB
CLAUDE.md
Context for AI assistants — the Claude GitHub App (@claude) and contributors using Claude — working in
this repo. Humans: also read doc/CodingStandard.md.
Project
MangosOne — The Burning Crusade World of Warcraft 2.4.3 server (C++, MySQL/MariaDB). Compatibility target is 2.4.3 only; do not introduce 2.5+/TBC or later-expansion assumptions.
- Database changes go in the separate
mangosone/databaserepo, not here — as transactional, idempotentRel##_##_###_*.sqlmigrations that chain viadb_version. - Clone/update recursively:
dep,src/realmd,src/modules/{SD3,Eluna}andwinare submodules — those four and no others. Never shallow-update a submodule to a non-tip pinned SHA. - Less-obvious locations: scripting lives in
src/modules/— Eluna (Lua) and SD3 (C++) are submodules; Bots (playerbots) is in-tree. The AuctionHouseBot is insrc/game/AuctionHouseBot/. The client-data baker is in-tree atsrc/tools/extractor/(the oldExtractor_projectssubmodule is gone).
Build & test
C++17 — strict (-std=c++17, GNU extensions off); C code is C11. CMake ≥ 3.18; GCC/Clang
(Linux/macOS/BSD) or MSVC ≥ 2015 (Windows). The exact flags CI builds with:
git clone --recursive https://github.com/mangosone/server.git && cd server
sudo apt-get install -y git cmake ninja-build ccache \
libssl-dev libbz2-dev default-libmysqlclient-dev libreadline-dev # Debian/Ubuntu deps
cmake -S . -B ../build -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../build/install \
-DBUILD_TOOLS=1 -DBUILD_MANGOSD=1 -DBUILD_REALMD=1 \
-DWITH_TESTS=1 -DWITH_NET_TESTS=0 -DSOAP=1 \
-DSCRIPT_LIB_ELUNA=1 -DSCRIPT_LIB_SD3=1 -DPLAYERBOTS=1 \
-DPCH=0
cmake --build ../build --parallel && cmake --install ../build
Build out of source, outside the working tree. A build directory inside the repo can make a stale
relative #include "../../dep/foo.h" resolve by accident, so the build passes and the broken path
survives; building outside is what exposes it.
Every -D above is a real option (see the option(...) block in CMakeLists.txt). CMake silently ignores
an unknown -D — it only mutters "Manually-specified variables were not used" at the end — so a misspelt
flag looks like it works while configuring nothing. Check the name against CMakeLists.txt before adding one.
BUILD_TOOLS no longer gates the baker. src/CMakeLists.txt adds tools/extractor unconditionally,
and says why: the fused .tile files it produces are what src/shared/terrain reads at runtime, so it
is not optional the way the old map/vmap extractors were. The unit tests also link its client-data parsers
directly. BUILD_TOOLS now only decides whether the extractor executable is built; CI passes
-DBUILD_TOOLS=1, so extractor changes are compiled by every CI run. Navmesh generation lives inside it
(src/tools/extractor/nav/) rather than in a separate Movemap generator.
Two runtime couplings follow, and both bite at deploy time:
- The tile format carries a version, and a bake from an older extractor is refused outright — no height, no liquid, no collision for that tile. Rebuild the extractor and re-run it before serving a branch that bumped the version; the old binary writes the old format.
- The extractor links
dataintegrityand is what writesdata.manifest, the SHA-256 listing thatWorld::VerifyDataIntegritychecks at start-up (DataIntegrityCheck: 0 off, 1 report, 2 refuse). A data set with no manifest is reported and accepted, never refused — so "no data.manifest; unverified" at boot means the bake predates the manifest, not that anything is wrong.
Windows: use the EasyBuild helper in win/. A PR MUST keep CI green. CI is GitHub Actions
(.github/workflows/): core_linux_build.yml builds with both GCC and Clang, core_windows_build.yml
builds with MSVC, core_codestyle.yml checks the style rules below, and docker_build.yml builds the images.
The GCC/Clang split matters more than it looks: the two standard libraries do not leak the same headers, so
a missing #include can pass on one and fail on the other. Include what you use — if a file names
std::vector, it includes <vector> itself rather than inheriting it from some header four levels up.
Code style
Source of truth: doc/CodingStandard.md. Non-default rules:
- 4-space indent, never tabs; ~80-column lines.
- Allman braces, and YOU MUST brace single-statement blocks — even one-line
if/for/while. Do not de-brace existing ones. - One space before
(, none inside:if (x), notif( x ). - Doxygen:
///above a member,///<trailing,/** ... */multi-line.
Repository etiquette
- Branches:
type/kebab-description(feature/…,fix/…,docs/…). Never push straight tomaster. - Keep PRs small and single-purpose. Large multi-commit PRs are hard to review and can exceed the
@claudereviewer's budget (it reacts 👀 but may never post). For a big change, ask@claudeto review one subsystem/file range at a time rather than the whole branch.
Architecture note
mangosd is the sole authority over game state. The world runs as a single heartbeat loop on the main
thread (Master::WorldLoop); everything else — the console, remote access, SOAP, the freeze watchdog, the
DB delay threads — is auxiliary and must not mutate world state directly. Anything arriving from another
thread is queued to the world thread (see World::QueueCliCommand) rather than applied where it landed.
The AuctionHouseBot (src/game/AuctionHouseBot/) runs in-process.
Logging
Console output is rendered on a dedicated off-thread writer (src/shared/Log/ConsoleLogWriter) so the
world/map-update threads never block on console I/O. Two rules follow:
- Never write to stdout directly (
printf/fprintf, progress bars, ad-hoc notices) for console output — route it throughLog::ConsoleEmitRawso stdout has a single owner and lines can't tear against, or overtake, the writer's output. - Gate high-volume runtime debug with
DEBUG_FILTER_LOG(LOG_FILTER_*, …)(orDETAIL_/BASIC_), reusing an existingLogFiltersbit where one fits. All filters ship default-on (suppressed); set aLogFilter_*key to0to see a category. Never filteroutError/outErrorDb— errors must always show.
Recommended runtime mode: LogLevel=1 (quiet console) + LogFileLevel=3 (buffered full file).
Review focus (for @claude)
Prioritise: (1) correctness/safety in src/game/ handlers and anything touching live world or DB state,
especially cross-thread state (the shutdown signal, the CLI command queue, the DB delay threads);
(2) coding-standard conformance above; (3) build/CI impact — GCC and Clang and MSVC, including
missing #includes that only one standard library exposes; (4) DB-migration correctness (use the
mangosone/database pattern). Keep feedback concrete and minimal-diff; flag correctness/standard issues, not
style preferences the standard doesn't cover.