Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
a05161d
Add headless world chat client
paleophyte Jul 7, 2026
2e7e081
Merge remote-tracking branch 'origin/master' into codex/headless-chat…
paleophyte Jul 8, 2026
e4957be
Add fleet visibility dashboard
paleophyte Jul 8, 2026
8f88576
Clarify fleet dashboard connection states
paleophyte Jul 8, 2026
f849b31
Tolerate partial fleet dashboard polling failures
paleophyte Jul 8, 2026
77c03af
Stream fleet leader logs in debug mode
paleophyte Jul 8, 2026
52f7fff
Show newest dashboard chat first
paleophyte Jul 8, 2026
1407a07
Flush logger stdout for live debug streaming
paleophyte Jul 8, 2026
290d07a
Add abstract fleet leader map
paleophyte Jul 8, 2026
1c37d76
Use MiniManager zone art in fleet map
paleophyte Jul 8, 2026
62b5a4d
Harden fleet dashboard polling and map view
paleophyte Jul 8, 2026
f4b1fa0
Add bot fleet pathfinding and travel planning tools
paleophyte Jul 9, 2026
df4b942
Merge wip/tbc-deeprun-tram-portals: deeprun tram/portal fixes
paleophyte Jul 10, 2026
3fa5cf7
Merge fix/tbc-deeprun-tram-boarding: EntityManager thread-safety
paleophyte Jul 10, 2026
5cb89f4
feat(automation): opt leaders into full world-object simulation for t…
paleophyte Jul 10, 2026
883545d
Merge fix/tbc-deeprun-tram-boarding: shared M2 boarding/registration …
paleophyte Jul 10, 2026
d424899
Merge fix/tbc-deeprun-tram-boarding: AssetManager loose-file DBC fall…
paleophyte Jul 10, 2026
eb0ef42
feat(automation): wire headless transport registration and M2 boarding
paleophyte Jul 10, 2026
32359f3
fix(automation): follow the transport's live position while riding
paleophyte Jul 10, 2026
05c2801
Merge fix/tbc-deeprun-tram-boarding: absolute-time transport phase se…
paleophyte Jul 10, 2026
56deb98
Merge fix/tbc-deeprun-tram-boarding: stop clobbering the phase seed o…
paleophyte Jul 10, 2026
2dabd18
Merge fix/tbc-deeprun-tram-boarding: preserve transports on DESTROY_O…
paleophyte Jul 10, 2026
8162ec4
Merge fix/tbc-deeprun-tram-boarding: fix M2 transport riding identity…
paleophyte Jul 10, 2026
d763b0f
Merge fix/tbc-deeprun-tram-boarding: tighten boarding radius + walk-w…
paleophyte Jul 10, 2026
77da3c5
Merge fix/tbc-deeprun-tram-boarding: third phase-seed, fall-through, …
paleophyte Jul 10, 2026
2808b12
Merge tram seed-duration, boarding-radius, and grade-clip fixes for h…
paleophyte Jul 10, 2026
2e47c7e
Merge station-anchor plausibility guard for headless regression testing
paleophyte Jul 10, 2026
be39d87
Merge boarding diagnostic promotion for headless branch parity
paleophyte Jul 10, 2026
ed0463a
Merge boarding vertical-threshold fix for headless branch parity
paleophyte Jul 10, 2026
b03d930
Merge disembark radius fix for headless branch parity
paleophyte Jul 10, 2026
37791d1
Merge disembark margin widening for headless branch parity
paleophyte Jul 10, 2026
365cbf4
Merge falling-animation, tilt-revert, and disembark sanity-guard fixe…
paleophyte Jul 10, 2026
c51caff
Merge ride offset runaway clamp for headless branch parity
paleophyte Jul 10, 2026
2eda64b
Merge movement-input gate for ride offset accumulation, headless bran…
paleophyte Jul 10, 2026
b981fc5
Merge entry 176085 path-direction fix for headless branch parity
paleophyte Jul 10, 2026
29f27ea
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
fdb7a5a
Expose TransportManager's live simulated position via /world/entities
paleophyte Jul 10, 2026
5abc71c
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
fee7223
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
91cb083
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
9eb1738
Merge fix/tbc-deeprun-tram-boarding (incl. upstream sync) for headles…
paleophyte Jul 10, 2026
21bb627
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
47d56c8
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
d06d6cd
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
f620928
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
92278df
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
27bb1b2
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
e5708f5
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 10, 2026
11953fc
Merge branch 'fix/tbc-deeprun-tram-boarding' into codex/headless-chat…
paleophyte Jul 11, 2026
bdabf4d
fix(headless): wire asset manager into GameServices, fix transport di…
paleophyte Jul 11, 2026
8d25a72
docs(bot-plan): add Phase 6-8 for combat/progression, fleet demo, and…
paleophyte Jul 11, 2026
44ce51a
Merge branch 'master' into codex/headless-chat-client
paleophyte Jul 11, 2026
6f46d96
docs(bot-plan): add Grand Expedition definition of done, note resume-…
paleophyte Jul 11, 2026
b3f4926
fix(bot-fleet): dwell-detect tram arrival instead of a fixed coordina…
paleophyte Jul 11, 2026
c9f5803
feat(bot-plan): plan Wetlands-crossing safety, implement route death-…
paleophyte Jul 11, 2026
6956d7a
fix(bot-fleet): add ironforge-gate-south waypoint past a navmesh chok…
paleophyte Jul 11, 2026
9b63542
feat(headless): expose release-spirit/reclaim-corpse over the HTTP API
paleophyte Jul 11, 2026
19e37cc
docs(bot-plan): record the Ironforge gate navmesh fix and death-recov…
paleophyte Jul 11, 2026
dc6dfab
chore(ops): add scoped MoveMapGen sudo rule for mangos-helper
paleophyte Jul 11, 2026
198574b
feat(bot-fleet): add recover-death orchestration on top of the releas…
paleophyte Jul 11, 2026
53b4262
docs(bot-plan): record the Loch Modan navmesh stall past Thelsamar
paleophyte Jul 11, 2026
78c8954
fix(movement): correctly parse pre-WotLK MSG_MOVE_TELEPORT_ACK
paleophyte Jul 11, 2026
272eb4e
feat(bot-fleet): add a live-player follow script for road surveying
paleophyte Jul 11, 2026
7cfb76a
docs(bot-plan): record the tunnel void hazard and the goto Z-interpol…
paleophyte Jul 11, 2026
f9644c2
feat(headless): expose a clean logout over the HTTP API
paleophyte Jul 11, 2026
e190742
feat(bot-fleet): auto-resume the interrupted route after death recovery
paleophyte Jul 11, 2026
5a56e6f
feat(headless): expose hostility/NPC flags and spirit-healer resurrec…
paleophyte Jul 11, 2026
371f946
feat(bot-fleet): reroute route-goto around hostile creatures
paleophyte Jul 11, 2026
e0375be
fix(bot-fleet): rescan for hostiles periodically during a leg, not ju…
paleophyte Jul 11, 2026
8e36af0
feat(bot-fleet): catalog human-walked routes and replay them
paleophyte Jul 11, 2026
3db920f
docs(bot-plan): record the avoidance system results and the survey-ca…
paleophyte Jul 11, 2026
b47aa40
chore(ops): add a scoped world-DB read-only query grant for mangos-he…
paleophyte Jul 11, 2026
b798439
fix(ops): stop query_world_db.sh silently dying under set -e
paleophyte Jul 11, 2026
46e031c
chore(ops): let mangos-helper self-deploy query_world_db.sh fixes
paleophyte Jul 11, 2026
7346ae8
fix(headless): make headlessModeEnabled() prefer WOWEE_HEADLESS over …
paleophyte Jul 12, 2026
7659c3b
fix(movement): correctly parse packed guid in other-player movement r…
paleophyte Jul 12, 2026
57e4f0e
fix(bot-fleet): resume from existing catalog in follow_player.py inst…
paleophyte Jul 12, 2026
1ed438d
docs(bot-plan): record the completed Wetlands human-follow survey to …
paleophyte Jul 12, 2026
a9a1bc4
feat(headless): add /learn-flight-path endpoint, fix dead isKnownTaxi…
paleophyte Jul 12, 2026
4b58f39
docs(bot-plan): extend the Wetlands survey catalog to Menethil's Flig…
paleophyte Jul 12, 2026
b16e6e4
feat(headless): list all currently-known taxi nodes in /world/self
paleophyte Jul 12, 2026
ce958a1
feat(bot-fleet): add --reverse and --resume-through-death to replay-s…
paleophyte Jul 12, 2026
60d463a
docs(bot-plan): record the reverse survey-replay run and queue the re…
paleophyte Jul 12, 2026
2d6981d
feat(bot-fleet): choose ghost-walk vs spirit-healer recovery by estim…
paleophyte Jul 12, 2026
d184757
docs(bot-plan): mark the death-recovery efficiency calculation done
paleophyte Jul 12, 2026
3f033eb
feat(bot-fleet): resume-through-death and auto-learn-flight-paths for…
paleophyte Jul 12, 2026
76011b2
docs(bot-plan): record the completed Ironforge return trip and intera…
paleophyte Jul 12, 2026
992cb61
feat(movement): make /follow actually walk toward the target, expose …
paleophyte Jul 12, 2026
152f484
docs(bot-plan): record the real /follow movement feature
paleophyte Jul 12, 2026
46a2a11
tune(movement): tighten /follow stop distance from 4y to 1y
paleophyte Jul 12, 2026
a123207
docs(bot-plan): record the upstream sync and a review of relevant Wot…
paleophyte Jul 12, 2026
60fdbec
Merge branch 'master' into feat/headless-bot-fleet
paleophyte Jul 12, 2026
a166417
fix(headless): build the faction hostility map on headless world-entry
paleophyte Jul 12, 2026
831aeba
fix(security): resolve Semgrep CI findings in Python tooling
paleophyte Jul 12, 2026
c1b8c97
docs: add CLAUDE.md with the shared-vs-headless branch-splitting process
paleophyte Jul 12, 2026
20411dc
docs(bot-plan): drop stale "(Later)" qualifier from Phase 3c heading
paleophyte Jul 12, 2026
a7b14cc
fix(taxi): drive flight-path simulation off MovementHandler's real state
paleophyte Jul 12, 2026
9986819
Merge branch 'master' into feat/headless-bot-fleet
paleophyte Jul 12, 2026
b67a5dc
fix(build): wire the new wowee_version target into wowee_headless
paleophyte Jul 12, 2026
1050edd
fix(movement): correct operator precedence in SMSG_CLIENT_CONTROL_UPD…
paleophyte Jul 12, 2026
7047012
feat(headless): add /taxi/activate endpoint to exercise flight paths
paleophyte Jul 12, 2026
9c6e150
feat(headless): add taxi_flight_demo.py to trace a real flight end to…
paleophyte Jul 12, 2026
8f2e2ca
debug(taxi): log floor candidates during the post-taxi landing clamp
paleophyte Jul 12, 2026
0a76784
debug(taxi): log mount configure/clear events with taxiFlight state
paleophyte Jul 12, 2026
71afc27
fix(taxi): prefer WMO/M2 floor over raw terrain in the post-landing c…
paleophyte Jul 12, 2026
711bbd0
debug(taxi): log every dismount call site to find the mid-flight trigger
paleophyte Jul 13, 2026
6bf8bec
fix(taxi): ignore SMSG_DISMOUNT while a client taxi flight is active
paleophyte Jul 13, 2026
ec36210
Merge branch 'master' into feat/headless-bot-fleet
paleophyte Jul 13, 2026
e438886
fix(taxi): ignore mid-flight UNIT_FIELD_MOUNTDISPLAYID drop to 0
paleophyte Jul 13, 2026
91b447e
perf(terrain): batch distant-tile unload across frames, time GPU clea…
paleophyte Jul 13, 2026
33d1fae
Merge branch 'master' into feat/headless-bot-fleet
paleophyte Jul 13, 2026
4efded9
docs(claude-md): clarify when Claude may open the upstream PR directly
paleophyte Jul 13, 2026
11f94b8
fix(taxi): defer flight activation until server confirms, disambiguat…
paleophyte Jul 13, 2026
924c585
fix(taxi): select landing-clamp floor by proximity, not by source
paleophyte Jul 13, 2026
25a27e4
fix(taxi): time out a taxi activation reply that never arrives
paleophyte Jul 13, 2026
b48be90
fix(bot-fleet): stop swallowing auto-learn-flight-paths failures sile…
paleophyte Jul 13, 2026
28924d7
Add AzerothCore provisioning support
paleophyte Jul 13, 2026
bb79e5b
Default provisioned accounts to moderator
paleophyte Jul 13, 2026
4294336
fix(bot-fleet): don't discard the response body on HTTP error status
paleophyte Jul 13, 2026
56e7a09
fix(bot-fleet): default fullWorldSimulation to true
paleophyte Jul 13, 2026
fe180d0
feat(headless): expose player money via /world/self
paleophyte Jul 13, 2026
d1c3710
fix(auth): use explicit legacyVanillaRealmList flag for realm-list pa…
paleophyte Jul 13, 2026
2b1c6c9
feat(provisioning): add VMangos server profile support
paleophyte Jul 13, 2026
a07625b
feat(taxi): gray out unaffordable destinations in the flight-map UI
paleophyte Jul 13, 2026
db7bdcb
fix(taxi): correct VMangos-specific teleport-ack and flight-master bugs
paleophyte Jul 13, 2026
aa4b295
Merge pull request #4 from paleophyte/feat/headless-bot-fleet
paleophyte Jul 13, 2026
534074f
fix(taxi): don't arm landing clamp on a merely-pending activation
paleophyte Jul 13, 2026
8d7ae6c
fix(terrain): time-budget tile unloads instead of a fixed per-frame c…
paleophyte Jul 13, 2026
e01a869
fix(taxi): pace client-simulated flight by curve arc length, not chord
paleophyte Jul 13, 2026
e971aec
fix(taxi): snap to TaxiNodes.dbc position, not the path's last waypoint
paleophyte Jul 13, 2026
3bab474
fix(taxi): push landing position corrections to the renderer directly
paleophyte Jul 13, 2026
5b18547
docs: don't build wowee GUI target on this VM by default
paleophyte Jul 13, 2026
3dea72e
Merge remote-tracking branch 'upstream/master'
paleophyte Jul 13, 2026
406f278
docs(claude-md): reflect PR #4's effect on master and update fix-bran…
paleophyte Jul 13, 2026
a296b89
merge: sync master (fork-sync reconciliation + CLAUDE.md policy update)
paleophyte Jul 13, 2026
fcd6695
fix(taxi): don't arm landing clamp on a merely-pending activation
paleophyte Jul 13, 2026
96ea486
perf(terrain): batch distant-tile unload across frames, time GPU clea…
paleophyte Jul 13, 2026
897bb01
fix(terrain): time-budget tile unloads instead of a fixed per-frame c…
paleophyte Jul 13, 2026
70e03e4
fix(taxi): pace client-simulated flight by curve arc length, not chord
paleophyte Jul 13, 2026
bfc06a6
fix(taxi): snap to TaxiNodes.dbc position, not the path's last waypoint
paleophyte Jul 13, 2026
823f3f3
fix(taxi): push landing position corrections to the renderer directly
paleophyte Jul 13, 2026
69a6ebd
fix(auth): use SRP protocol v8 for classic expansion profile
paleophyte Jul 13, 2026
4747758
fix(auth): use SRP protocol v8 for classic expansion profile
paleophyte Jul 13, 2026
f8f1990
merge: sync fresh upstream/master before forwarding this PR
paleophyte Jul 13, 2026
a882a2d
merge: bring in the upstream-synced taxi/terrain fix branch
paleophyte Jul 13, 2026
5a028a1
Merge remote-tracking branch 'upstream/master'
paleophyte Jul 13, 2026
c55448d
merge: bring master's terrain-unload code up to date
paleophyte Jul 13, 2026
fc0daae
merge: sync master's terrain-unload update
paleophyte Jul 13, 2026
3a9285c
merge: sync upstream asset profile support
paleophyte Jul 13, 2026
a41c1dc
merge: sync upstream animation and inventory fixes
paleophyte Jul 14, 2026
e26d2a5
Support Turtle headless provisioning
paleophyte Jul 15, 2026
7df76d6
Merge master into feat/headless-bot-fleet
paleophyte Jul 15, 2026
ca09681
chore(provisioning): document Turtle SHA1 auth compatibility
paleophyte Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ imgui.ini
config.ini
config.json
.env
client/
tools/.env
tools/headless_client/settings.json
tools/bot_fleet_manager/fleet.settings.json
tools/bot_fleet_manager/runtime/
tools/provisioning/*.local.json
tools/provisioning/roster.json

# Runtime cache (floor heights, etc.)
cache/
Expand All @@ -106,9 +113,11 @@ asset_pipeline/
# Local texture dumps / extracted art should never be committed
assets/textures/
node_modules/
vcpkg_installed/

# Python cache artifacts
tools/__pycache__/
**/__pycache__/
*.pyc

# World editor output: scaffolded/exported zones and per-user ImGui layout
Expand Down
256 changes: 256 additions & 0 deletions BOT_PLAN.md

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# WoWee repo notes for Claude

## Two remotes, two audiences

- `origin` (`paleophyte/WoWee`) - this fork. Headless bot-fleet work
(`tools/headless_client/`, `tools/bot_fleet_manager/`, `tools/world_db_query/`,
`tools/provisioning/`, `BOT_PLAN.md`, the `WOWEE_HEADLESS`/`WOWEE_HEADLESS_DEFAULT`
build machinery) lives here only - none of it exists upstream, so it can't
meaningfully be split out or PR'd there.
- `upstream` (`Kelsidavis/WoWee`) - the original project. Only bug fixes and
improvements to code that exists in *both* trees (`src/game/`, `include/game/`,
`src/core/`, `src/ui/`, `src/rendering/`, etc. - the GUI/shared client) belong here.

This file itself is fork-specific context. It originally lived only on
`feat/headless-bot-fleet` on the assumption `master` would stay a clean
upstream mirror - as of 2026-07-13, `origin/master` (this fork's master, not
upstream's) had the entire `feat/headless-bot-fleet` branch merged into it
directly (PR #4), so it now permanently carries the full headless-bot-fleet
content, this file included. That's fine on its own terms (headless work
living only in this fork was always the intent - see above), but it means
**`origin/master`/local `master` can no longer be assumed clean for cutting
shared-code fix branches**. Use `upstream/master` (fetched fresh via
`git fetch upstream`) as the base for those instead - see below.

## Don't build the `wowee` GUI target on this machine

This is a VM with no GUI testing use - the user pulls this repo to their Mac
or Windows laptop (whichever matches the platform they want to test) and
builds/runs `wowee` there. `wowee`'s compile time is significant, so treat
that cycle as expensive and avoid spending it here by default.

- Default to building only `wowee_headless` to verify shared-code changes
compile - that's almost always sufficient, since `wowee` and
`wowee_headless` share the same source for anything outside
`tools/headless_client/` and `WOWEE_HEADLESS`-gated branches.
- CI (GitHub Actions, `Build (windows-x86-64)`/`(x86-64)`/`(macOS arm64)`/etc.)
already builds and validates `wowee` for every PR - that's the normal way
a `wowee`-side compile error gets caught, not a local build here.
- If something seems like it could *specifically* require compiling `wowee`
locally to prove (e.g. a GUI-only code path CI can't exercise, or CI itself
is failing in a way that needs local repro) - stop and ask the user for
confirmation first, explaining exactly why the headless-only build or CI
isn't enough for this specific case. Don't just build it "to be thorough."

## When fixing a bug in shared code

If a fix touches a file that also exists upstream (not just something under
`tools/headless_client/` or gated behind `WOWEE_HEADLESS`), cut a small,
focused branch for it off **`upstream/master`** (not local/`origin` `master`
- see the note above about why that's no longer a clean base) *in addition
to* whatever work is happening on this feature branch - don't let it get
stuck waiting for a future retroactive extraction. Precedent:
`fix/area-trigger-dbc-load-race` was done this way and is already merged
upstream as PR #91.

1. `git fetch upstream` and diff the target function/file against
`upstream/master` to confirm the bug is still actually there (not already
fixed independently) - don't assume the local history summary is still
accurate.
2. `git checkout -b fix/<short-name> upstream/master` (or `feat/<short-name>`
for a genuine improvement, not a bug fix).
3. Apply *only* the shared-code hunks - if the same commit on this branch
also touched a headless-only call site (e.g. a new HTTP endpoint in
`tools/headless_client/main.cpp` that exercises the fix), leave that part
out. Check `git diff upstream/master feat/headless-bot-fleet -- <file>`
first; several shared files have accumulated unrelated headless-only
hunks (env-var gating, new headless-only methods) mixed in from other
work, so don't blindly `git checkout <branch> -- <file>` a whole file
without checking what's actually in its diff.
4. Build `wowee_headless` against the new branch before committing (see
"Don't build the `wowee` GUI target on this machine" above for why not
both - CI covers `wowee` once pushed).
5. Push and open a PR against `paleophyte/WoWee` `master` first - never
open the upstream PR before this one exists and its CI is clean.
6. Once that PR's local CI is green, `git fetch upstream` again and check
`git log --oneline <fix-branch>..upstream/master`. This confirms the fix
branch is still current *at the moment of forwarding*, not just when it
was cut - upstream moves fast enough that new commits can land during
the CI run itself.
- **Not behind**: open the PR directly against `Kelsidavis/WoWee`
`master` - this is pre-authorized, no need to check back first.
- **Behind, and the new upstream commits don't touch this fix's files**:
open the PR anyway: unrelated upstream churn isn't a reason to hold it.
- **Behind, and a new upstream commit touches the same function/file**:
do not open the PR yet. Re-run the full sync cycle first - merge fresh
`upstream/master` into the shared-code fix branch (and into
`feat/headless-bot-fleet` separately, if it also carries this fix),
resolve conflicts (favor whichever side has real, currently-working
logic over a duplicate/dead code path - see the `updateTaxiAndMountState()`
precedent from 2026-07-12 for the reasoning to apply), rebuild
`wowee_headless`, push, and wait for CI to go green again before
re-checking upstream and opening the PR.

Keep each branch to one logical fix - small and reviewable, matching the
PR #91 precedent, not one giant "everything shared" branch.
102 changes: 102 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ option(WOWEE_ENABLE_TRACY "Enable Tracy profiler instrumentation" OFF)
option(WOWEE_ENABLE_AMD_FSR2 "Enable AMD FidelityFX FSR2 backend when SDK is present" ON)
option(WOWEE_ENABLE_AMD_FSR3_FRAMEGEN "Enable AMD FidelityFX SDK FSR3 frame generation interface probe when SDK is present" ON)
option(WOWEE_BUILD_AMD_FSR3_RUNTIME "Build native AMD FidelityFX VK runtime (Path A) from extern/FidelityFX-SDK/Kits" ON)
set(WOWEE_MANGOS_TBC_DIR "C:/Users/admin/code/mangos-tbc" CACHE PATH "Optional CMaNGOS TBC checkout used to build mmap_path_query")

# AMD FidelityFX FSR2 SDK detection (drop-in under extern/FidelityFX-FSR2)
set(WOWEE_AMD_FSR2_DIR ${CMAKE_SOURCE_DIR}/extern/FidelityFX-FSR2)
Expand Down Expand Up @@ -507,6 +508,7 @@ set(WOWEE_SOURCES
src/core/window.cpp
src/core/input.cpp
src/core/logger.cpp
src/core/crash_diagnostics.cpp
src/core/memory_monitor.cpp

# Math
Expand Down Expand Up @@ -1463,6 +1465,106 @@ set_target_properties(auth_login_probe PROPERTIES
)
install(TARGETS auth_login_probe RUNTIME DESTINATION bin)

set(WOWEE_HEADLESS_SOURCES ${WOWEE_SOURCES})
list(REMOVE_ITEM WOWEE_HEADLESS_SOURCES src/main.cpp)
add_executable(wowee_headless
tools/headless_client/main.cpp
${WOWEE_HEADLESS_SOURCES}
)
target_compile_definitions(wowee_headless PRIVATE WOWEE_HEADLESS_DEFAULT=1)
if(TARGET opcodes-generate)
add_dependencies(wowee_headless opcodes-generate)
endif()
add_dependencies(wowee_headless wowee_version)
target_include_directories(wowee_headless PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/generated
)
target_include_directories(wowee_headless SYSTEM PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/extern
${CMAKE_CURRENT_SOURCE_DIR}/extern/vk-bootstrap/src
)
if(HAVE_FFMPEG)
target_compile_definitions(wowee_headless PRIVATE HAVE_FFMPEG)
target_include_directories(wowee_headless PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(wowee_headless PRIVATE ${FFMPEG_LIBRARIES})
if(FFMPEG_LIBRARY_DIRS)
target_link_directories(wowee_headless PRIVATE ${FFMPEG_LIBRARY_DIRS})
endif()
endif()
target_link_libraries(wowee_headless PRIVATE
SDL2::SDL2
Vulkan::Vulkan
OpenSSL::SSL
OpenSSL::Crypto
Threads::Threads
ZLIB::ZLIB
lua51
${CMAKE_DL_LIBS}
)
if(UNIX AND NOT APPLE)
target_link_libraries(wowee_headless PRIVATE X11)
endif()
if(WIN32)
target_link_libraries(wowee_headless PRIVATE ws2_32)
endif()
if(TARGET imgui)
target_link_libraries(wowee_headless PRIVATE imgui)
endif()
if(TARGET vk-bootstrap)
target_link_libraries(wowee_headless PRIVATE vk-bootstrap)
endif()
if(TARGET wowee_fsr2_amd_vk)
target_link_libraries(wowee_headless PRIVATE wowee_fsr2_amd_vk)
endif()
if(TARGET wowee_fsr3_framegen_amd_vk_probe)
target_link_libraries(wowee_headless PRIVATE wowee_fsr3_framegen_amd_vk_probe)
endif()
if(HAVE_UNICORN)
target_link_libraries(wowee_headless PRIVATE ${UNICORN_LIBRARY})
target_include_directories(wowee_headless PRIVATE ${UNICORN_INCLUDE_DIR})
target_compile_definitions(wowee_headless PRIVATE HAVE_UNICORN)
endif()
if(TARGET glm::glm)
target_link_libraries(wowee_headless PRIVATE glm::glm)
elseif(glm_FOUND)
target_include_directories(wowee_headless PRIVATE ${GLM_INCLUDE_DIRS})
endif()
set_target_properties(wowee_headless PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS wowee_headless RUNTIME DESTINATION bin)

# ---- Tool: mmap_path_query (CMaNGOS mmap/Detour JSON path helper) ----
set(WOWEE_DETOUR_DIR "${WOWEE_MANGOS_TBC_DIR}/dep/recastnavigation/Detour")
if(EXISTS "${WOWEE_DETOUR_DIR}/Include/DetourNavMesh.h")
add_executable(mmap_path_query
tools/pathfinding_service/mmap_path_query.cpp
${WOWEE_DETOUR_DIR}/Source/DetourAlloc.cpp
${WOWEE_DETOUR_DIR}/Source/DetourAssert.cpp
${WOWEE_DETOUR_DIR}/Source/DetourCommon.cpp
${WOWEE_DETOUR_DIR}/Source/DetourNavMesh.cpp
${WOWEE_DETOUR_DIR}/Source/DetourNavMeshBuilder.cpp
${WOWEE_DETOUR_DIR}/Source/DetourNavMeshQuery.cpp
${WOWEE_DETOUR_DIR}/Source/DetourNode.cpp
)
target_include_directories(mmap_path_query PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/extern
${WOWEE_DETOUR_DIR}/Include
)
target_compile_definitions(mmap_path_query PRIVATE DT_POLYREF64)
set_target_properties(mmap_path_query PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
install(TARGETS mmap_path_query RUNTIME DESTINATION bin)
message(STATUS " mmap_path_query tool: ENABLED (${WOWEE_MANGOS_TBC_DIR})")
else()
message(STATUS " mmap_path_query tool: DISABLED (set WOWEE_MANGOS_TBC_DIR to a CMaNGOS TBC checkout)")
endif()

# ---- Tool: blp_convert (BLP ↔ PNG) ----
add_executable(blp_convert
tools/blp_convert/main.cpp
Expand Down
17 changes: 17 additions & 0 deletions include/core/crash_diagnostics.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <cstddef>
#include <cstdint>

namespace wowee::core {

void installCrashDiagnostics(const char* processLabel);
void setCrashBreadcrumb(const char* phase,
uint16_t wireOpcode,
const char* logicalOpcode,
std::size_t packetSize,
std::size_t readPos,
int worldState);
void setCrashNote(const char* note);

} // namespace wowee::core
3 changes: 3 additions & 0 deletions include/game/entity_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class EntityController {
void queryPlayerName(uint64_t guid);
void queryCreatureInfo(uint32_t entry, uint64_t guid);
void queryGameObjectInfo(uint32_t entry, uint64_t guid);
void cachePlayerName(uint64_t guid, const std::string& name) {
if (guid != 0 && !name.empty()) playerNameCache[guid] = name;
}
std::string getCachedPlayerName(uint64_t guid) const;
std::string getCachedCreatureName(uint32_t entry) const;
void invalidatePlayerName(uint64_t guid) { playerNameCache.erase(guid); }
Expand Down
8 changes: 5 additions & 3 deletions include/game/faction_hostility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ class GameHandler;
// GameHandler::isHostileFaction() defaults an unrecognized faction template
// ID to hostile=true (a reasonable default once the map is actually
// populated, since anything left out by the DBC-driven loop below is
// genuinely unusual). Call this once per session, as soon as playerRace is
// known and the asset manager is initialized, or every faction template
// will fall through to that hostile default.
// genuinely unusual). The headless client never called this, so the map
// stayed permanently empty and *everything* read as hostile - live-observed
// at Menethil Harbor as ~20 false-positive "threats" including town guards,
// friendly party bots, and a critter. Call this once per session, as soon
// as playerRace is known and the asset manager is initialized.
void buildFactionHostilityMap(pipeline::AssetManager& assetManager, GameHandler& gameHandler, uint8_t playerRace);

} // namespace game
Expand Down
14 changes: 14 additions & 0 deletions include/game/game_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ class GameHandler : public IConnectionState,
// Instance difficulty
void sendSetDifficulty(uint32_t difficulty);
bool isLoggingOut() const;
bool isLogoutComplete() const;
float getLogoutCountdown() const;

// Stand state
Expand Down Expand Up @@ -648,6 +649,9 @@ class GameHandler : public IConnectionState,
void queryPlayerName(uint64_t guid);
void queryCreatureInfo(uint32_t entry, uint64_t guid);
void queryGameObjectInfo(uint32_t entry, uint64_t guid);
void cachePlayerName(uint64_t guid, const std::string& name) {
entityController_->cachePlayerName(guid, name);
}
const GameObjectQueryResponseData* getCachedGameObjectInfo(uint32_t entry) const {
return entityController_->getCachedGameObjectInfo(entry);
}
Expand Down Expand Up @@ -1192,6 +1196,7 @@ class GameHandler : public IConnectionState,
bool hasServerTransportUpdate(uint64_t guid) const { return entityController_->hasServerTransportUpdate(guid); }
glm::vec3 getComposedWorldPosition(); // Compose transport transform * local offset
TransportManager* getTransportManager() { return transportManager_.get(); }
const TransportManager* getTransportManager() const { return transportManager_.get(); }
// Client-side M2 transport (trams, lifts) board/disembark check by proximity to the
// transport's live position. Call once per tick with the player's current canonical
// world position; safe to call whether or not any M2 transports are registered.
Expand Down Expand Up @@ -1307,6 +1312,10 @@ class GameHandler : public IConnectionState,
outY = corpseX_; // server X = canonical Y (west)
return true;
}
/** Corpse Z (up); only meaningful when getCorpseCanonicalPos() returns true. */
float getCorpseZ() const { return corpseZ_; }
/** Map the corpse is on, or 0 if no corpse data yet. */
uint32_t getCorpseMapId() const { return corpseMapId_; }
/** Send CMSG_RECLAIM_CORPSE; noop if not a ghost or not near corpse. */
void reclaimCorpse();
void releaseSpirit();
Expand Down Expand Up @@ -1515,6 +1524,10 @@ class GameHandler : public IConnectionState,
// NPC Gossip
void interactWithNpc(uint64_t guid);
void interactWithGameObject(uint64_t guid);
// Sends CMSG_TAXIQUERYAVAILABLENODES directly (what a real client sends
// when clicking a flight master, instead of CMSG_GOSSIP_HELLO) - see
// queryTaxiNodes() usage in headless_client/main.cpp for why.
void queryTaxiNodes(uint64_t guid);
void selectGossipOption(uint32_t optionId);
void selectGossipQuest(uint32_t questId);
void acceptQuest();
Expand Down Expand Up @@ -2023,6 +2036,7 @@ class GameHandler : public IConnectionState,
using TaxiPathEdge = MovementHandler::TaxiPathEdge;
using TaxiPathNode = MovementHandler::TaxiPathNode;
const std::unordered_map<uint32_t, TaxiNode>& getTaxiNodes() const;
const std::vector<TaxiPathEdge>& getTaxiPathEdges() const;
bool isKnownTaxiNode(uint32_t nodeId) const;
uint32_t getTaxiCostTo(uint32_t destNodeId) const;
bool taxiNpcHasRoutes(uint64_t guid) const {
Expand Down
5 changes: 5 additions & 0 deletions include/game/game_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

#include "game/expansion_profile.hpp"
#include "core/application.hpp"
#include <cstdlib>
#include <string>

namespace wowee {
namespace game {

inline bool isActiveExpansion(const char* expansionId) {
if (const char* env = std::getenv("WOWEE_ACTIVE_EXPANSION")) {
if (*env) return std::string(env) == expansionId;
}
auto& app = core::Application::getInstance();
auto* registry = app.getExpansionRegistry();
if (!registry) return false;
Expand Down
1 change: 1 addition & 0 deletions include/game/movement_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class MovementHandler {
};

const std::unordered_map<uint32_t, TaxiNode>& getTaxiNodes() const { return taxiNodes_; }
const std::vector<TaxiPathEdge>& getTaxiPathEdges() const { return taxiPathEdges_; }
// WotLK 3.3.5a TaxiNodes.dbc has 384 entries; the known-taxi bitmask
// is 12 × uint32 = 384 bits. Node IDs outside this range are invalid.
static constexpr uint32_t kMaxTaxiNodeId = 384;
Expand Down
3 changes: 2 additions & 1 deletion include/game/protocol_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ constexpr uint32_t SPELL_SHADOWFORM = 15473;
constexpr uint32_t RX_SILENCE_WARNING_MS = 10000; // 10 s
constexpr uint32_t RX_SILENCE_CRITICAL_MS = 15000; // 15 s
constexpr float WARDEN_GATE_LOG_INTERVAL_SEC = 30.0f;
constexpr float CLASSIC_PING_INTERVAL_SEC = 10.0f;
// CMaNGOS classic/TBC treats pings under ~27s apart as overspeed pings.
constexpr float CLASSIC_PING_INTERVAL_SEC = 30.0f;

// ---------------------------------------------------------------------------
// Heartbeat / area-trigger intervals (seconds)
Expand Down
5 changes: 5 additions & 0 deletions include/game/social_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class SocialHandler {
void cancelLogout();
bool isLoggingOut() const { return loggingOut_; }
float getLogoutCountdown() const { return logoutCountdown_; }
// Distinct from isLoggingOut(), which goes back to false once the
// logout finishes - this stays true so callers (e.g. the headless
// client's shutdown loop) can tell "never logged out" from "done".
bool isLogoutComplete() const { return logoutComplete_; }
bool isLogoutToExit() const { return exitAfterLogout_; }

// Guild
Expand Down Expand Up @@ -368,6 +372,7 @@ class SocialHandler {

// Logout
bool loggingOut_ = false;
bool logoutComplete_ = false;
bool exitAfterLogout_ = false;
float logoutCountdown_ = 0.0f;

Expand Down
Loading
Loading