Kelsidavis-WoWee/include/core/world_loader.hpp
Pavel Okhlopkov fff06fc932 refactor: decompose world map into modular component architecture
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>
2026-04-12 09:52:51 +03:00

126 lines
4.3 KiB
C++

#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>
#include <memory>
#include <atomic>
#include <thread>
#include <cstdint>
namespace wowee {
namespace rendering { class Renderer; }
namespace pipeline { class AssetManager; class DBCLayout; }
namespace game { class GameHandler; class World; }
namespace addons { class AddonManager; }
namespace core {
class Application;
class EntitySpawner;
class AppearanceComposer;
class Window;
/// Handles terrain streaming, map transitions, world preloading,
/// and coordinate-aware tile management for online world entry.
class WorldLoader {
public:
WorldLoader(Application& app,
rendering::Renderer* renderer,
pipeline::AssetManager* assetManager,
game::GameHandler* gameHandler,
EntitySpawner* entitySpawner,
AppearanceComposer* appearanceComposer,
Window* window,
game::World* world,
addons::AddonManager* addonManager);
~WorldLoader();
// Main terrain loading — drives loading screen, WMO/ADT detection, player spawn
void loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float z);
// Process deferred world entry (called from Application::update each frame)
void processPendingEntry();
// Map name utilities
static const char* mapIdToName(uint32_t mapId);
static int mapNameToId(const std::string& name);
static const char* mapDisplayName(uint32_t mapId);
// Background preloading — warms AssetManager file cache
void startWorldPreload(uint32_t mapId, const std::string& mapName,
float serverX, float serverY);
void cancelWorldPreload();
// Persistent world info for session-to-session preloading
void saveLastWorldInfo(uint32_t mapId, const std::string& mapName,
float serverX, float serverY);
struct LastWorldInfo {
uint32_t mapId = 0;
std::string mapName;
float x = 0, y = 0;
bool valid = false;
};
LastWorldInfo loadLastWorldInfo() const;
// State accessors
uint32_t getLoadedMapId() const { return loadedMapId_; }
bool isLoadingWorld() const { return loadingWorld_; }
bool hasPendingEntry() const { return pendingWorldEntry_.has_value(); }
// Get cached map name by ID (returns empty string if not found)
std::string getMapNameById(uint32_t mapId) const {
auto it = mapNameById_.find(mapId);
return (it != mapNameById_.end()) ? it->second : std::string{};
}
// Set pending world entry for deferred processing via processPendingEntry()
void setPendingEntry(uint32_t mapId, float x, float y, float z) {
pendingWorldEntry_ = PendingWorldEntry{mapId, x, y, z};
}
// Reset methods (for logout / character switch)
void resetLoadedMap() { loadedMapId_ = 0xFFFFFFFF; }
void resetMapNameCache() { mapNameCacheLoaded_ = false; mapNameById_.clear(); }
private:
Application& app_;
rendering::Renderer* renderer_;
pipeline::AssetManager* assetManager_;
game::GameHandler* gameHandler_;
EntitySpawner* entitySpawner_;
AppearanceComposer* appearanceComposer_;
Window* window_;
game::World* world_;
addons::AddonManager* addonManager_;
uint32_t loadedMapId_ = 0xFFFFFFFF; // Map ID of currently loaded terrain (0xFFFFFFFF = none)
uint32_t worldLoadGeneration_ = 0; // Incremented on each world entry to detect re-entrant loads
bool loadingWorld_ = false; // True while loadOnlineWorldTerrain is running
struct PendingWorldEntry {
uint32_t mapId; float x, y, z;
};
std::optional<PendingWorldEntry> pendingWorldEntry_;
// Map.dbc name cache (loaded once per session)
bool mapNameCacheLoaded_ = false;
std::unordered_map<uint32_t, std::string> mapNameById_;
// Background world preloader — warms AssetManager file cache for the
// expected world before the user clicks Enter World.
struct WorldPreload {
uint32_t mapId = 0;
std::string mapName;
int centerTileX = 0;
int centerTileY = 0;
std::atomic<bool> cancel{false};
std::vector<std::thread> workers;
};
std::unique_ptr<WorldPreload> worldPreload_;
};
} // namespace core
} // namespace wowee