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>
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,10 @@ bool Map::removeThingByPos(const Position& pos, int stackPos)
return false;
}
template <typename... Items>
TilePtr Map::createTileEx(const Position& pos, const Items&... items)
const TilePtr& Map::createTile(const Position& pos)
{
TilePtr tile = getOrCreateTile(pos);
auto vec = {items...};
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.isValid())
return m_nulltile;
if(pos.x < m_tilesRect.left())
m_tilesRect.setLeft(pos.x);
if(pos.y < m_tilesRect.top())
@ -725,38 +716,63 @@ TilePtr Map::createTile(const Position& pos)
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 <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;
}
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)
{
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));
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);
notificateTileUpdateToMapViews(pos);
}
}
}

View File

@ -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<TilePtr, BLOCK_SIZE*BLOCK_SIZE> 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 <typename... Items>
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<std::vector<Otc::Direction>, 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<uint, TileBlock> m_tileBlocks[Otc::MAX_Z+1];
std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
std::vector<AnimatedTextPtr> m_animatedTexts;
@ -237,6 +272,7 @@ private:
Houses m_houses;
Towns m_towns;
Creatures m_creatures;
static TilePtr m_nulltile;
};
extern Map g_map;

View File

@ -218,7 +218,7 @@ public:
struct PositionHasher : std::unary_function<Position, std::size_t> {
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;
}
};