Optimize map tile storage

Tiles are stored in blocks of 32x32 now, improving tile allocation and access speed
This commit is contained in:
Eduardo Bart 2012-07-29 03:23:27 -03:00
parent e0431021b5
commit 29a4d467af
3 changed files with 101 additions and 49 deletions

View File

@ -37,6 +37,7 @@
#include <framework/xml/tinyxml.h> #include <framework/xml/tinyxml.h>
Map g_map; Map g_map;
TilePtr Map::m_nulltile;
void Map::terminate() 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)); 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."); g_logger.debug("OTBM read successfully.");
fin->close(); fin->close();
@ -251,6 +246,7 @@ void Map::loadOtbm(const std::string& fileName)
void Map::saveOtbm(const std::string &fileName) void Map::saveOtbm(const std::string &fileName)
{ {
#if 0
/// FIXME: Untested code /// FIXME: Untested code
FileStreamPtr fin = g_resources.appendFile(fileName); FileStreamPtr fin = g_resources.appendFile(fileName);
if(!fin) if(!fin)
@ -384,6 +380,7 @@ void Map::saveOtbm(const std::string &fileName)
root->writeToFile(); root->writeToFile();
g_logger.debug(stdext::format("OTBM saving took %ld", time(0) - start)); g_logger.debug(stdext::format("OTBM saving took %ld", time(0) - start));
#endif
} }
void Map::loadSpawns(const std::string &fileName) void Map::loadSpawns(const std::string &fileName)
@ -472,7 +469,7 @@ bool Map::loadOtcm(const std::string& fileName)
if(!pos.isValid()) if(!pos.isValid())
break; break;
TilePtr tile = g_map.createTile(pos); const TilePtr& tile = g_map.createTile(pos);
int stackPos = 0; int stackPos = 0;
while(true) { while(true) {
@ -503,6 +500,7 @@ bool Map::loadOtcm(const std::string& fileName)
void Map::saveOtcm(const std::string& fileName) void Map::saveOtcm(const std::string& fileName)
{ {
#if 0
try { try {
g_clock.update(); g_clock.update();
@ -566,12 +564,16 @@ void Map::saveOtcm(const std::string& fileName)
} catch(stdext::exception& e) { } catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); g_logger.error(stdext::format("failed to save OTCM map: %s", e.what()));
} }
#endif
} }
void Map::clean() void Map::clean()
{ {
cleanDynamicThings(); cleanDynamicThings();
m_tiles.clear();
for(int i=0;i<=Otc::MAX_Z;++i)
m_tileBlocks[i].clear();
m_waypoints.clear(); m_waypoints.clear();
m_towns.clear(); m_towns.clear();
@ -702,21 +704,10 @@ bool Map::removeThingByPos(const Position& pos, int stackPos)
return false; return false;
} }
template <typename... Items> const TilePtr& Map::createTile(const Position& pos)
TilePtr Map::createTileEx(const Position& pos, const Items&... items)
{ {
TilePtr tile = getOrCreateTile(pos); if(!pos.isValid())
auto vec = {items...}; return m_nulltile;
for (auto it : vec)
addThing(it, pos);
return tile;
}
TilePtr Map::createTile(const Position& pos)
{
TilePtr tile = TilePtr(new Tile(pos));
m_tiles[pos] = tile;
if(pos.x < m_tilesRect.left()) if(pos.x < m_tilesRect.left())
m_tilesRect.setLeft(pos.x); m_tilesRect.setLeft(pos.x);
if(pos.y < m_tilesRect.top()) if(pos.y < m_tilesRect.top())
@ -725,40 +716,65 @@ TilePtr Map::createTile(const Position& pos)
m_tilesRect.setRight(pos.x); m_tilesRect.setRight(pos.x);
if(pos.y > m_tilesRect.bottom()) if(pos.y > m_tilesRect.bottom())
m_tilesRect.setBottom(pos.y); m_tilesRect.setBottom(pos.y);
TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)];
return block.create(pos);
}
template <typename... Items>
const TilePtr& Map::createTileEx(const Position& pos, const Items&... items)
{
if(!pos.isValid())
return m_nulltile;
const TilePtr& tile = getOrCreateTile(pos);
auto vec = {items...};
for(auto it : vec)
addThing(it, pos);
return tile; return tile;
} }
const TilePtr& Map::getOrCreateTile(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.getOrCreate(pos);
}
const TilePtr& Map::getTile(const Position& pos) const TilePtr& Map::getTile(const Position& pos)
{ {
static TilePtr nulltile; if(!pos.isValid())
if(!m_tilesRect.contains(Point(pos.x, pos.y))) return m_nulltile;
return nulltile; auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos));
if(it != m_tileBlocks[pos.z].end())
auto it = m_tiles.find(pos); return it->second.get(pos);
if(it != m_tiles.end()) return m_nulltile;
return it->second;
return nulltile;
}
TilePtr Map::getOrCreateTile(const Position& pos)
{
const TilePtr& tile = getTile(pos);
if(tile)
return tile;
else
return createTile(pos);
} }
void Map::cleanTile(const Position& pos) void Map::cleanTile(const Position& pos)
{ {
if(TilePtr tile = getTile(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(); tile->clean();
if(tile->canErase()) if(tile->canErase())
m_tiles.erase(m_tiles.find(pos)); block.remove(pos);
notificateTileUpdateToMapViews(pos); notificateTileUpdateToMapViews(pos);
} }
} }
}
void Map::addCreature(const CreaturePtr& creature) void Map::addCreature(const CreaturePtr& creature)
{ {

View File

@ -135,6 +135,39 @@ enum {
OTCM_VERSION = 1 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<TilePtr, BLOCK_SIZE*BLOCK_SIZE> m_tiles;
};
//@bindsingleton g_map //@bindsingleton g_map
class Map class Map
{ {
@ -181,11 +214,11 @@ public:
bool removeThingByPos(const Position& pos, int stackPos); bool removeThingByPos(const Position& pos, int stackPos);
// tile related // tile related
const TilePtr& createTile(const Position& pos);
template <typename... Items> template <typename... Items>
TilePtr createTileEx(const Position& pos, const Items&... items); const TilePtr& createTileEx(const Position& pos, const Items&... items);
TilePtr createTile(const Position& pos); const TilePtr& getOrCreateTile(const Position& pos);
const TilePtr& getTile(const Position& pos); const TilePtr& getTile(const Position& pos);
TilePtr getOrCreateTile(const Position& pos);
void cleanTile(const Position& pos); void cleanTile(const Position& pos);
// known creature related // known creature related
@ -221,7 +254,9 @@ public:
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps); std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps);
private: private:
TileMap m_tiles; uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); }
std::unordered_map<uint, TileBlock> m_tileBlocks[Otc::MAX_Z+1];
std::unordered_map<uint32, CreaturePtr> m_knownCreatures; std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles; std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
std::vector<AnimatedTextPtr> m_animatedTexts; std::vector<AnimatedTextPtr> m_animatedTexts;
@ -237,6 +272,7 @@ private:
Houses m_houses; Houses m_houses;
Towns m_towns; Towns m_towns;
Creatures m_creatures; Creatures m_creatures;
static TilePtr m_nulltile;
}; };
extern Map g_map; extern Map g_map;

View File

@ -218,7 +218,7 @@ public:
struct PositionHasher : std::unary_function<Position, std::size_t> { struct PositionHasher : std::unary_function<Position, std::size_t> {
std::size_t operator()(const Position& pos) const { 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;
} }
}; };