Use zone-specific floor cache files

Save/load floor cache per map (e.g., cache/wmo_floor_Azeroth.bin) instead
of a single global file. Saves current zone's cache before teleporting,
loads target zone's cache after terrain streaming completes.
This commit is contained in:
Kelsi 2026-02-05 17:35:17 -08:00
parent 1530900bc7
commit 76c4268ed8
5 changed files with 60 additions and 21 deletions

3
.gitignore vendored
View file

@ -61,3 +61,6 @@ Data/
# Texture assets (not distributed - see README) # Texture assets (not distributed - see README)
assets/textures/ assets/textures/
# Runtime cache (floor heights, etc.)
cache/

Binary file not shown.

View file

@ -222,9 +222,11 @@ public:
double getQueryTimeMs() const { return queryTimeMs; } double getQueryTimeMs() const { return queryTimeMs; }
uint32_t getQueryCallCount() const { return queryCallCount; } uint32_t getQueryCallCount() const { return queryCallCount; }
// Floor cache persistence // Floor cache persistence (zone-specific files)
bool saveFloorCache(const std::string& filepath) const; void setMapName(const std::string& name) { mapName_ = name; }
bool loadFloorCache(const std::string& filepath); const std::string& getMapName() const { return mapName_; }
bool saveFloorCache() const; // Saves to cache/wmo_floor_<mapName>.bin
bool loadFloorCache(); // Loads from cache/wmo_floor_<mapName>.bin
size_t getFloorCacheSize() const { return precomputedFloorGrid.size(); } size_t getFloorCacheSize() const { return precomputedFloorGrid.size(); }
// Pre-compute floor cache for all loaded WMO instances // Pre-compute floor cache for all loaded WMO instances
@ -428,6 +430,9 @@ private:
// Asset manager for loading textures // Asset manager for loading textures
pipeline::AssetManager* assetManager = nullptr; pipeline::AssetManager* assetManager = nullptr;
// Current map name for zone-specific floor cache
std::string mapName_;
// Texture cache (path -> texture ID) // Texture cache (path -> texture ID)
std::unordered_map<std::string, GLuint> textureCache; std::unordered_map<std::string, GLuint> textureCache;

View file

@ -146,11 +146,6 @@ bool Application::initialize() {
return false; return false;
} }
// Load cached floor heights for faster collision
if (renderer->getWMORenderer()) {
renderer->getWMORenderer()->loadFloorCache("cache/wmo_floor_cache.bin");
}
// Create UI manager // Create UI manager
uiManager = std::make_unique<ui::UIManager>(); uiManager = std::make_unique<ui::UIManager>();
if (!uiManager->initialize(window.get())) { if (!uiManager->initialize(window.get())) {
@ -320,7 +315,7 @@ void Application::shutdown() {
size_t cacheSize = renderer->getWMORenderer()->getFloorCacheSize(); size_t cacheSize = renderer->getWMORenderer()->getFloorCacheSize();
if (cacheSize > 0) { if (cacheSize > 0) {
LOG_INFO("Saving WMO floor cache (", cacheSize, " entries)..."); LOG_INFO("Saving WMO floor cache (", cacheSize, " entries)...");
renderer->getWMORenderer()->saveFloorCache("cache/wmo_floor_cache.bin"); renderer->getWMORenderer()->saveFloorCache();
} }
} }
@ -1207,6 +1202,11 @@ void Application::startSinglePlayer() {
showStatus("Loading terrain..."); showStatus("Loading terrain...");
// Set map name for zone-specific floor cache
if (renderer->getWMORenderer()) {
renderer->getWMORenderer()->setMapName(mapName);
}
// Try to load test terrain if WOW_DATA_PATH is set // Try to load test terrain if WOW_DATA_PATH is set
bool terrainOk = false; bool terrainOk = false;
if (renderer && assetManager && assetManager->isInitialized()) { if (renderer && assetManager && assetManager->isInitialized()) {
@ -1270,10 +1270,13 @@ void Application::startSinglePlayer() {
LOG_INFO("Terrain streaming complete: ", terrainMgr->getLoadedTileCount(), " tiles loaded"); LOG_INFO("Terrain streaming complete: ", terrainMgr->getLoadedTileCount(), " tiles loaded");
// Pre-compute floor cache if it wasn't loaded from file // Load zone-specific floor cache, or precompute if none exists
if (renderer->getWMORenderer() && renderer->getWMORenderer()->getFloorCacheSize() == 0) { if (renderer->getWMORenderer()) {
showStatus("Pre-computing collision cache..."); renderer->getWMORenderer()->loadFloorCache();
renderer->getWMORenderer()->precomputeFloorCache(); if (renderer->getWMORenderer()->getFloorCacheSize() == 0) {
showStatus("Pre-computing collision cache...");
renderer->getWMORenderer()->precomputeFloorCache();
}
} }
// Re-snap camera to ground now that all surrounding tiles are loaded // Re-snap camera to ground now that all surrounding tiles are loaded
@ -1348,6 +1351,14 @@ void Application::teleportTo(int presetIndex) {
renderer->getCameraController()->setDefaultSpawn(spawnRender, preset.yawDeg, preset.pitchDeg); renderer->getCameraController()->setDefaultSpawn(spawnRender, preset.yawDeg, preset.pitchDeg);
} }
// Save current map's floor cache before unloading
if (renderer && renderer->getWMORenderer()) {
auto* wmo = renderer->getWMORenderer();
if (wmo->getFloorCacheSize() > 0) {
wmo->saveFloorCache();
}
}
// Unload all current terrain // Unload all current terrain
if (renderer && renderer->getTerrainManager()) { if (renderer && renderer->getTerrainManager()) {
renderer->getTerrainManager()->unloadAll(); renderer->getTerrainManager()->unloadAll();
@ -1360,10 +1371,13 @@ void Application::teleportTo(int presetIndex) {
std::to_string(tileX) + "_" + std::to_string(tileY) + ".adt"; std::to_string(tileX) + "_" + std::to_string(tileY) + ".adt";
LOG_INFO("Teleport ADT tile [", tileX, ",", tileY, "]"); LOG_INFO("Teleport ADT tile [", tileX, ",", tileY, "]");
// Set map name on terrain manager // Set map name on terrain manager and WMO renderer
if (renderer && renderer->getTerrainManager()) { if (renderer && renderer->getTerrainManager()) {
renderer->getTerrainManager()->setMapName(mapName); renderer->getTerrainManager()->setMapName(mapName);
} }
if (renderer && renderer->getWMORenderer()) {
renderer->getWMORenderer()->setMapName(mapName);
}
// Load the initial tile // Load the initial tile
bool terrainOk = false; bool terrainOk = false;
@ -1403,9 +1417,12 @@ void Application::teleportTo(int presetIndex) {
LOG_INFO("Teleport terrain streaming complete: ", terrainMgr->getLoadedTileCount(), " tiles loaded"); LOG_INFO("Teleport terrain streaming complete: ", terrainMgr->getLoadedTileCount(), " tiles loaded");
// Pre-compute floor cache for the new area // Load zone-specific floor cache, or precompute if none exists
if (renderer->getWMORenderer()) { if (renderer->getWMORenderer()) {
renderer->getWMORenderer()->precomputeFloorCache(); renderer->getWMORenderer()->loadFloorCache();
if (renderer->getWMORenderer()->getFloorCacheSize() == 0) {
renderer->getWMORenderer()->precomputeFloorCache();
}
} }
} }

View file

@ -514,7 +514,14 @@ void WMORenderer::resetQueryStats() {
// Note: precomputedFloorGrid is persistent and not cleared per-frame // Note: precomputedFloorGrid is persistent and not cleared per-frame
} }
bool WMORenderer::saveFloorCache(const std::string& filepath) const { bool WMORenderer::saveFloorCache() const {
if (mapName_.empty()) {
core::Logger::getInstance().warning("Cannot save floor cache: no map name set");
return false;
}
std::string filepath = "cache/wmo_floor_" + mapName_ + ".bin";
// Create directory if needed // Create directory if needed
std::filesystem::path path(filepath); std::filesystem::path path(filepath);
std::filesystem::path absPath = std::filesystem::absolute(path); std::filesystem::path absPath = std::filesystem::absolute(path);
@ -549,14 +556,21 @@ bool WMORenderer::saveFloorCache(const std::string& filepath) const {
file.write(reinterpret_cast<const char*>(&height), sizeof(height)); file.write(reinterpret_cast<const char*>(&height), sizeof(height));
} }
core::Logger::getInstance().info("Saved WMO floor cache: ", count, " entries to ", filepath); core::Logger::getInstance().info("Saved WMO floor cache (", mapName_, "): ", count, " entries");
return true; return true;
} }
bool WMORenderer::loadFloorCache(const std::string& filepath) { bool WMORenderer::loadFloorCache() {
if (mapName_.empty()) {
core::Logger::getInstance().warning("Cannot load floor cache: no map name set");
return false;
}
std::string filepath = "cache/wmo_floor_" + mapName_ + ".bin";
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (!file) { if (!file) {
core::Logger::getInstance().info("No existing floor cache file: ", filepath); core::Logger::getInstance().info("No existing floor cache for map: ", mapName_);
return false; return false;
} }
@ -585,7 +599,7 @@ bool WMORenderer::loadFloorCache(const std::string& filepath) {
precomputedFloorGrid[key] = height; precomputedFloorGrid[key] = height;
} }
core::Logger::getInstance().info("Loaded WMO floor cache: ", precomputedFloorGrid.size(), " entries from ", filepath); core::Logger::getInstance().info("Loaded WMO floor cache (", mapName_, "): ", precomputedFloorGrid.size(), " entries");
return true; return true;
} }