Optimize map tile storage
Tiles are stored in blocks of 32x32 now, improving tile allocation and access speed
This commit is contained in:
parent
e0431021b5
commit
29a4d467af
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue