From 29a4d467af9c1f2145de805d2dfc43e32672024b Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sun, 29 Jul 2012 03:23:27 -0300 Subject: [PATCH] Optimize map tile storage Tiles are stored in blocks of 32x32 now, improving tile allocation and access speed --- src/otclient/map.cpp | 92 ++++++++++++++++++++++++----------------- src/otclient/map.h | 44 ++++++++++++++++++-- src/otclient/position.h | 2 +- 3 files changed, 95 insertions(+), 43 deletions(-) diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 25676ec8..c744a45e 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -37,6 +37,7 @@ #include Map g_map; +TilePtr Map::m_nulltile; void Map::terminate() { @@ -236,12 +237,6 @@ void Map::loadOtbm(const std::string& fileName) stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); } - int numItems = 0; - for(const auto& it : m_tiles) - numItems += it.second->getThingCount(); - - g_logger.debug(stdext::format("Total items: %d", numItems)); - g_logger.debug(stdext::format("Total tiles: %d", m_tiles.size())); g_logger.debug("OTBM read successfully."); fin->close(); @@ -251,6 +246,7 @@ void Map::loadOtbm(const std::string& fileName) void Map::saveOtbm(const std::string &fileName) { +#if 0 /// FIXME: Untested code FileStreamPtr fin = g_resources.appendFile(fileName); if(!fin) @@ -384,6 +380,7 @@ void Map::saveOtbm(const std::string &fileName) root->writeToFile(); g_logger.debug(stdext::format("OTBM saving took %ld", time(0) - start)); +#endif } void Map::loadSpawns(const std::string &fileName) @@ -472,7 +469,7 @@ bool Map::loadOtcm(const std::string& fileName) if(!pos.isValid()) break; - TilePtr tile = g_map.createTile(pos); + const TilePtr& tile = g_map.createTile(pos); int stackPos = 0; while(true) { @@ -503,6 +500,7 @@ bool Map::loadOtcm(const std::string& fileName) void Map::saveOtcm(const std::string& fileName) { +#if 0 try { g_clock.update(); @@ -566,12 +564,16 @@ void Map::saveOtcm(const std::string& fileName) } catch(stdext::exception& e) { g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); } +#endif } void Map::clean() { cleanDynamicThings(); - m_tiles.clear(); + + for(int i=0;i<=Otc::MAX_Z;++i) + m_tileBlocks[i].clear(); + m_waypoints.clear(); m_towns.clear(); @@ -702,21 +704,39 @@ bool Map::removeThingByPos(const Position& pos, int stackPos) return false; } +const TilePtr& Map::createTile(const Position& pos) +{ + if(!pos.isValid()) + return m_nulltile; + if(pos.x < m_tilesRect.left()) + m_tilesRect.setLeft(pos.x); + if(pos.y < m_tilesRect.top()) + m_tilesRect.setTop(pos.y); + if(pos.x > m_tilesRect.right()) + m_tilesRect.setRight(pos.x); + if(pos.y > m_tilesRect.bottom()) + m_tilesRect.setBottom(pos.y); + TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)]; + return block.create(pos); +} + template -TilePtr Map::createTileEx(const Position& pos, const Items&... items) +const TilePtr& Map::createTileEx(const Position& pos, const Items&... items) { - TilePtr tile = getOrCreateTile(pos); + if(!pos.isValid()) + return m_nulltile; + const TilePtr& tile = getOrCreateTile(pos); auto vec = {items...}; - for (auto it : vec) + for(auto it : vec) addThing(it, pos); return tile; } -TilePtr Map::createTile(const Position& pos) +const TilePtr& Map::getOrCreateTile(const Position& pos) { - TilePtr tile = TilePtr(new Tile(pos)); - m_tiles[pos] = tile; + if(!pos.isValid()) + return m_nulltile; if(pos.x < m_tilesRect.left()) m_tilesRect.setLeft(pos.x); if(pos.y < m_tilesRect.top()) @@ -725,38 +745,34 @@ TilePtr Map::createTile(const Position& pos) m_tilesRect.setRight(pos.x); if(pos.y > m_tilesRect.bottom()) m_tilesRect.setBottom(pos.y); - return tile; + TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)]; + return block.getOrCreate(pos); } const TilePtr& Map::getTile(const Position& pos) { - static TilePtr nulltile; - if(!m_tilesRect.contains(Point(pos.x, pos.y))) - return nulltile; - - auto it = m_tiles.find(pos); - if(it != m_tiles.end()) - return it->second; - return nulltile; -} - -TilePtr Map::getOrCreateTile(const Position& pos) -{ - const TilePtr& tile = getTile(pos); - if(tile) - return tile; - else - return createTile(pos); + if(!pos.isValid()) + return m_nulltile; + auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos)); + if(it != m_tileBlocks[pos.z].end()) + return it->second.get(pos); + return m_nulltile; } void Map::cleanTile(const Position& pos) { - if(TilePtr tile = getTile(pos)) { - tile->clean(); - if(tile->canErase()) - m_tiles.erase(m_tiles.find(pos)); - - notificateTileUpdateToMapViews(pos); + if(!pos.isValid()) + return; + auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos)); + if(it != m_tileBlocks[pos.z].end()) { + TileBlock& block = it->second; + if(const TilePtr& tile = block.get(pos)) { + tile->clean(); + if(tile->canErase()) + block.remove(pos); + + notificateTileUpdateToMapViews(pos); + } } } diff --git a/src/otclient/map.h b/src/otclient/map.h index ee33868e..7c76758e 100644 --- a/src/otclient/map.h +++ b/src/otclient/map.h @@ -135,6 +135,39 @@ enum { OTCM_VERSION = 1 }; + + +enum { + BLOCK_SIZE = 32 +}; + +class TileBlock { +public: + TileBlock() { m_tiles.fill(nullptr); } + + const TilePtr& create(const Position& pos) { + TilePtr& tile = m_tiles[getTileIndex(pos)]; + tile = TilePtr(new Tile(pos)); + return tile; + } + + const TilePtr& getOrCreate(const Position& pos) { + TilePtr& tile = m_tiles[getTileIndex(pos)]; + if(!tile) + tile = TilePtr(new Tile(pos)); + return tile; + } + + const TilePtr& get(const Position& pos) { return m_tiles[getTileIndex(pos)]; } + + void remove(const Position& pos) { m_tiles[getTileIndex(pos)] = nullptr; } + + uint getTileIndex(const Position& pos) { return ((pos.y % BLOCK_SIZE) * BLOCK_SIZE) + (pos.x % BLOCK_SIZE); } + +private: + std::array m_tiles; +}; + //@bindsingleton g_map class Map { @@ -181,11 +214,11 @@ public: bool removeThingByPos(const Position& pos, int stackPos); // tile related + const TilePtr& createTile(const Position& pos); template - TilePtr createTileEx(const Position& pos, const Items&... items); - TilePtr createTile(const Position& pos); + const TilePtr& createTileEx(const Position& pos, const Items&... items); + const TilePtr& getOrCreateTile(const Position& pos); const TilePtr& getTile(const Position& pos); - TilePtr getOrCreateTile(const Position& pos); void cleanTile(const Position& pos); // known creature related @@ -221,7 +254,9 @@ public: std::tuple, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps); private: - TileMap m_tiles; + uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); } + + std::unordered_map m_tileBlocks[Otc::MAX_Z+1]; std::unordered_map m_knownCreatures; std::array, Otc::MAX_Z+1> m_floorMissiles; std::vector m_animatedTexts; @@ -237,6 +272,7 @@ private: Houses m_houses; Towns m_towns; Creatures m_creatures; + static TilePtr m_nulltile; }; extern Map g_map; diff --git a/src/otclient/position.h b/src/otclient/position.h index 1729d84d..9c49c5b1 100644 --- a/src/otclient/position.h +++ b/src/otclient/position.h @@ -218,7 +218,7 @@ public: struct PositionHasher : std::unary_function { std::size_t operator()(const Position& pos) const { - return (((((pos.x * 8192) + pos.y) * 16) + pos.z) % (8192*8192)) % 100000000; + return (((pos.x * 8192) + pos.y) * 16) + pos.z; } };