mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-14 00:23:50 +00:00
Break the monolithic 1360-line world_map.cpp into 16 focused modules under src/rendering/world_map/: Architecture: - world_map_facade: public API composing all components (PIMPL) - world_map_types: Vulkan-free domain types (Zone, ViewLevel, etc.) - data_repository: DBC zone loading, ZMP pixel map, POI/overlay storage - coordinate_projection: UV projection, zone/continent lookups - composite_renderer: Vulkan tile pipeline + off-screen compositing - exploration_state: server mask + local exploration tracking - view_state_machine: COSMIC→WORLD→CONTINENT→ZONE navigation - input_handler: keyboard/mouse input → InputAction mapping - overlay_renderer: layer-based ImGui overlay system (OCP) - map_resolver: cross-map navigation (Outland, Northrend, etc.) - zone_metadata: level ranges and faction data Overlay layers (each an IOverlayLayer): - player_marker, party_dot, taxi_node, poi_marker, quest_poi, corpse_marker, zone_highlight, coordinate_display, subzone_tooltip Fixes: - Player marker no longer bleeds across continents (only shown when player is in a zone belonging to the displayed continent) - Zone hover uses DBC-projected AABB rectangles (restored from original working behavior) - Exploration overlay rendering for zone view subzones Tests: - 6 new test files covering coordinate projection, exploration state, map resolver, view state machine, zone metadata, and integration Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
198 lines
6.7 KiB
C++
198 lines
6.7 KiB
C++
// Tests for the extracted world map view state machine module
|
|
#include <catch_amalgamated.hpp>
|
|
#include "rendering/world_map/view_state_machine.hpp"
|
|
|
|
using namespace wowee::rendering::world_map;
|
|
|
|
TEST_CASE("ViewStateMachine: initial state is CONTINENT", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
REQUIRE(sm.currentLevel() == ViewLevel::CONTINENT);
|
|
REQUIRE(sm.continentIdx() == -1);
|
|
REQUIRE(sm.currentZoneIdx() == -1);
|
|
REQUIRE(sm.transition().active == false);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn from CONTINENT to ZONE", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
|
|
auto result = sm.zoomIn(5, 5);
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::ZONE);
|
|
REQUIRE(result.targetIdx == 5);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::ZONE);
|
|
REQUIRE(sm.currentZoneIdx() == 5);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn from CONTINENT with no zone does nothing", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
|
|
auto result = sm.zoomIn(-1, -1);
|
|
REQUIRE(result.changed == false);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::CONTINENT);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomOut from ZONE to CONTINENT", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::ZONE);
|
|
sm.setContinentIdx(0);
|
|
sm.setCurrentZoneIdx(5);
|
|
|
|
auto result = sm.zoomOut();
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::CONTINENT);
|
|
REQUIRE(result.targetIdx == 0);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::CONTINENT);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomOut from ZONE without continent does nothing", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::ZONE);
|
|
sm.setContinentIdx(-1);
|
|
|
|
auto result = sm.zoomOut();
|
|
REQUIRE(result.changed == false);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::ZONE);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomOut from CONTINENT to WORLD", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
|
|
auto result = sm.zoomOut();
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::WORLD);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::WORLD);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomOut from WORLD to COSMIC when enabled", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::WORLD);
|
|
sm.setCosmicEnabled(true);
|
|
|
|
auto result = sm.zoomOut();
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::COSMIC);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomOut from WORLD stays when cosmic disabled", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::WORLD);
|
|
sm.setCosmicEnabled(false);
|
|
|
|
auto result = sm.zoomOut();
|
|
REQUIRE(result.changed == false);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::WORLD);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn from COSMIC goes to WORLD", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::COSMIC);
|
|
sm.setCosmicEnabled(true);
|
|
|
|
auto result = sm.zoomIn(-1, -1);
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::WORLD);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn from WORLD to CONTINENT with continent set", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::WORLD);
|
|
sm.setContinentIdx(3);
|
|
|
|
auto result = sm.zoomIn(-1, -1);
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::CONTINENT);
|
|
REQUIRE(result.targetIdx == 3);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: enterWorldView sets WORLD level", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::ZONE);
|
|
|
|
auto result = sm.enterWorldView();
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::WORLD);
|
|
REQUIRE(sm.currentLevel() == ViewLevel::WORLD);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: enterCosmicView when disabled falls back to WORLD", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setCosmicEnabled(false);
|
|
|
|
auto result = sm.enterCosmicView();
|
|
REQUIRE(result.newLevel == ViewLevel::WORLD);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: enterZone goes to ZONE level", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
|
|
auto result = sm.enterZone(7);
|
|
REQUIRE(result.changed == true);
|
|
REQUIRE(result.newLevel == ViewLevel::ZONE);
|
|
REQUIRE(result.targetIdx == 7);
|
|
REQUIRE(sm.currentZoneIdx() == 7);
|
|
}
|
|
|
|
// ── Transition animation ─────────────────────────────────────
|
|
|
|
TEST_CASE("ViewStateMachine: transition starts on zoom", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
sm.zoomIn(5, 5);
|
|
|
|
REQUIRE(sm.transition().active == true);
|
|
REQUIRE(sm.transition().progress == Catch::Approx(0.0f));
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: updateTransition advances progress", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
sm.zoomIn(5, 5);
|
|
|
|
float halfDuration = sm.transition().duration / 2.0f;
|
|
bool stillActive = sm.updateTransition(halfDuration);
|
|
REQUIRE(stillActive == true);
|
|
REQUIRE(sm.transition().progress == Catch::Approx(0.5f).margin(0.01f));
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: transition completes after full duration", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
sm.zoomIn(5, 5);
|
|
|
|
float dur = sm.transition().duration;
|
|
sm.updateTransition(dur + 0.1f); // overshoot
|
|
REQUIRE(sm.transition().active == false);
|
|
REQUIRE(sm.transition().progress == Catch::Approx(1.0f));
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: updateTransition when no transition returns false", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
REQUIRE(sm.updateTransition(0.1f) == false);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn prefers hovered zone over player zone", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
|
|
auto result = sm.zoomIn(/*hovered=*/3, /*player=*/7);
|
|
REQUIRE(result.targetIdx == 3);
|
|
}
|
|
|
|
TEST_CASE("ViewStateMachine: zoomIn falls back to player zone when no hover", "[world_map][view_state_machine]") {
|
|
ViewStateMachine sm;
|
|
sm.setLevel(ViewLevel::CONTINENT);
|
|
sm.setContinentIdx(0);
|
|
|
|
auto result = sm.zoomIn(/*hovered=*/-1, /*player=*/7);
|
|
REQUIRE(result.targetIdx == 7);
|
|
}
|