mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Multiple optimizations to avoid copying and allocating tiles for rmg::Area
This commit is contained in:
@@ -19,12 +19,12 @@ namespace rmg
|
||||
|
||||
void toAbsolute(Tileset & tiles, const int3 & position)
|
||||
{
|
||||
Tileset temp;
|
||||
for(const auto & tile : tiles)
|
||||
std::vector vec(tiles.begin(), tiles.end());
|
||||
tiles.clear();
|
||||
std::transform(vec.begin(), vec.end(), vstd::set_inserter(tiles), [position](const int3 & tile)
|
||||
{
|
||||
temp.insert(tile + position);
|
||||
}
|
||||
tiles = std::move(temp);
|
||||
return tile + position;
|
||||
});
|
||||
}
|
||||
|
||||
void toRelative(Tileset & tiles, const int3 & position)
|
||||
@@ -161,6 +161,7 @@ const Tileset & Area::getBorder() const
|
||||
return dBorderCache;
|
||||
|
||||
//compute border cache
|
||||
dBorderCache.reserve(dTiles.bucket_count());
|
||||
for(const auto & t : dTiles)
|
||||
{
|
||||
for(auto & i : int3::getDirs())
|
||||
@@ -182,6 +183,7 @@ const Tileset & Area::getBorderOutside() const
|
||||
return dBorderOutsideCache;
|
||||
|
||||
//compute outside border cache
|
||||
dBorderOutsideCache.reserve(dBorderCache.bucket_count() * 2);
|
||||
for(const auto & t : dTiles)
|
||||
{
|
||||
for(auto & i : int3::getDirs())
|
||||
@@ -297,6 +299,7 @@ int3 Area::nearest(const Area & area) const
|
||||
Area Area::getSubarea(const std::function<bool(const int3 &)> & filter) const
|
||||
{
|
||||
Area subset;
|
||||
subset.dTiles.reserve(getTilesVector().size());
|
||||
vstd::copy_if(getTilesVector(), vstd::set_inserter(subset.dTiles), filter);
|
||||
return subset;
|
||||
}
|
||||
@@ -329,7 +332,8 @@ void Area::erase(const int3 & tile)
|
||||
void Area::unite(const Area & area)
|
||||
{
|
||||
invalidate();
|
||||
auto & vec = area.getTilesVector();
|
||||
const auto & vec = area.getTilesVector();
|
||||
dTiles.reserve(dTiles.size() + vec.size());
|
||||
dTiles.insert(vec.begin(), vec.end());
|
||||
}
|
||||
|
||||
@@ -337,6 +341,7 @@ void Area::intersect(const Area & area)
|
||||
{
|
||||
invalidate();
|
||||
Tileset result;
|
||||
result.reserve(std::max(dTiles.size(), area.getTilesVector().size()));
|
||||
for(const auto & t : area.getTilesVector())
|
||||
{
|
||||
if(dTiles.count(t))
|
||||
@@ -361,7 +366,6 @@ void Area::translate(const int3 & shift)
|
||||
|
||||
if(dTilesVectorCache.empty())
|
||||
{
|
||||
getTiles();
|
||||
getTilesVector();
|
||||
}
|
||||
|
||||
@@ -396,15 +400,22 @@ Area operator+ (const Area & l, const int3 & r)
|
||||
|
||||
Area operator+ (const Area & l, const Area & r)
|
||||
{
|
||||
Area result(l);
|
||||
result.unite(r);
|
||||
Area result;
|
||||
const auto & lTiles = l.getTilesVector();
|
||||
const auto & rTiles = r.getTilesVector();
|
||||
result.dTiles.reserve(lTiles.size() + rTiles.size());
|
||||
result.dTiles.insert(lTiles.begin(), lTiles.end());
|
||||
result.dTiles.insert(rTiles.begin(), rTiles.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
Area operator- (const Area & l, const Area & r)
|
||||
{
|
||||
Area result(l);
|
||||
result.subtract(r);
|
||||
for(const auto & t : r.getTilesVector())
|
||||
{
|
||||
result.dTiles.erase(t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -417,7 +428,7 @@ Area operator* (const Area & l, const Area & r)
|
||||
|
||||
bool operator== (const Area & l, const Area & r)
|
||||
{
|
||||
return l.getTiles() == r.getTiles();
|
||||
return l.getTilesVector() == r.getTilesVector();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ namespace rmg
|
||||
static const std::array<int3, 4> dirs4 = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0) };
|
||||
static const std::array<int3, 4> dirsDiagonal= { int3(1,1,0),int3(1,-1,0),int3(-1,1,0),int3(-1,-1,0) };
|
||||
|
||||
using Tileset = std::set<int3>;
|
||||
using Tileset = std::unordered_set<int3>;
|
||||
using DistanceMap = std::map<int3, int>;
|
||||
void toAbsolute(Tileset & tiles, const int3 & position);
|
||||
void toRelative(Tileset & tiles, const int3 & position);
|
||||
|
@@ -38,10 +38,11 @@ const Area & Object::Instance::getBlockedArea() const
|
||||
{
|
||||
if(dBlockedAreaCache.empty())
|
||||
{
|
||||
dBlockedAreaCache.assign(dObject.getBlockedPos());
|
||||
std::set<int3> blockedArea = dObject.getBlockedPos();
|
||||
dBlockedAreaCache.assign(rmg::Tileset(blockedArea.begin(), blockedArea.end()));
|
||||
if(dObject.isVisitable() || dBlockedAreaCache.empty())
|
||||
if (!dObject.isBlockedVisitable())
|
||||
// Do no assume blocked tile is accessible
|
||||
// Do not assume blocked tile is accessible
|
||||
dBlockedAreaCache.add(dObject.visitablePos());
|
||||
}
|
||||
return dBlockedAreaCache;
|
||||
@@ -71,7 +72,8 @@ const rmg::Area & Object::Instance::getAccessibleArea() const
|
||||
{
|
||||
auto neighbours = rmg::Area({getVisitablePosition()}).getBorderOutside();
|
||||
rmg::Area visitable = rmg::Area(neighbours) - getBlockedArea();
|
||||
for(const auto & from : visitable.getTiles())
|
||||
// TODO: Add in one operation to avoid multiple invalidation
|
||||
for(const auto & from : visitable.getTilesVector())
|
||||
{
|
||||
if(isVisitableFrom(from))
|
||||
dAccessibleAreaCache.add(from);
|
||||
|
@@ -95,7 +95,7 @@ void ObjectManager::updateDistances(std::function<ui32(const int3 & tile)> dista
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
tilesByDistance.clear();
|
||||
for (const auto & tile : zone.areaPossible().getTiles()) //don't need to mark distance for not possible tiles
|
||||
for (const auto & tile : zone.areaPossible().getTilesVector()) //don't need to mark distance for not possible tiles
|
||||
{
|
||||
ui32 d = distanceFunction(tile);
|
||||
map.setNearestObjectDistance(tile, std::min(static_cast<float>(d), map.getNearestObjectDistance(tile)));
|
||||
@@ -178,7 +178,7 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto & tile : searchArea.getTiles())
|
||||
for(const auto & tile : searchArea.getTilesVector())
|
||||
{
|
||||
obj.setPosition(tile);
|
||||
|
||||
@@ -469,7 +469,8 @@ bool ObjectManager::createRequiredObjects()
|
||||
}
|
||||
|
||||
rmg::Object rmgNearObject(*nearby.obj);
|
||||
rmg::Area possibleArea(rmg::Area(targetObject->getBlockedPos()).getBorderOutside());
|
||||
std::set<int3> blockedArea = targetObject->getBlockedPos();
|
||||
rmg::Area possibleArea(rmg::Area(rmg::Tileset(blockedArea.begin(), blockedArea.end())).getBorderOutside());
|
||||
possibleArea.intersect(zone.areaPossible());
|
||||
if(possibleArea.empty())
|
||||
{
|
||||
@@ -587,6 +588,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add multiple tiles in one operation to avoid multiple invalidation
|
||||
for(auto * instance : object.instances())
|
||||
{
|
||||
objectsVisitableArea.add(instance->getVisitablePosition());
|
||||
@@ -716,7 +718,7 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
|
||||
return false;
|
||||
|
||||
// Prefer non-blocking tiles, if any
|
||||
const auto & entrableTiles = object.getEntrableArea().getTiles();
|
||||
const auto & entrableTiles = object.getEntrableArea().getTilesVector();
|
||||
int3 entrableTile(-1, -1, -1);
|
||||
if (entrableTiles.empty())
|
||||
{
|
||||
|
@@ -51,7 +51,7 @@ void ObstaclePlacer::process()
|
||||
do
|
||||
{
|
||||
toBlock.clear();
|
||||
for (const auto& tile : zone.areaPossible().getTiles())
|
||||
for (const auto& tile : zone.areaPossible().getTilesVector())
|
||||
{
|
||||
rmg::Area neighbors;
|
||||
rmg::Area t;
|
||||
@@ -76,7 +76,7 @@ void ObstaclePlacer::process()
|
||||
}
|
||||
}
|
||||
zone.areaPossible().subtract(toBlock);
|
||||
for (const auto& tile : toBlock.getTiles())
|
||||
for (const auto& tile : toBlock.getTilesVector())
|
||||
{
|
||||
map.setOccupied(tile, ETileType::BLOCKED);
|
||||
}
|
||||
|
@@ -791,7 +791,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
||||
size_t size = 0;
|
||||
{
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
size = zone.getArea().getTiles().size();
|
||||
size = zone.getArea().getTilesVector().size();
|
||||
}
|
||||
|
||||
int totalDensity = 0;
|
||||
@@ -891,8 +891,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
||||
}
|
||||
|
||||
const auto & guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
||||
areaToBlock.subtract(guardedArea);
|
||||
const auto areaToBlock = rmgObject.getAccessibleArea(true) - guardedArea;
|
||||
|
||||
if (zone.freePaths().overlap(areaToBlock) || manager.getVisitableArea().overlap(areaToBlock))
|
||||
return -1.f;
|
||||
@@ -914,8 +913,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
||||
{
|
||||
guards.unite(rmgObject.instances().back()->getBlockedArea());
|
||||
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
||||
areaToBlock.subtract(guardedArea);
|
||||
auto areaToBlock = rmgObject.getAccessibleArea(true) - guardedArea;
|
||||
treasureBlockArea.unite(areaToBlock);
|
||||
}
|
||||
zone.connectPath(path);
|
||||
|
@@ -112,7 +112,7 @@ void WaterProxy::collectLakes()
|
||||
for(const auto & t : lake.getBorderOutside())
|
||||
if(map.isOnMap(t))
|
||||
lakes.back().neighbourZones[map.getZoneID(t)].add(t);
|
||||
for(const auto & t : lake.getTiles())
|
||||
for(const auto & t : lake.getTilesVector())
|
||||
lakeMap[t] = lakeId;
|
||||
|
||||
//each lake must have at least one free tile
|
||||
@@ -143,7 +143,7 @@ RouteInfo WaterProxy::waterRoute(Zone & dst)
|
||||
{
|
||||
if(!lake.keepConnections.count(dst.getId()))
|
||||
{
|
||||
for(const auto & ct : lake.neighbourZones[dst.getId()].getTiles())
|
||||
for(const auto & ct : lake.neighbourZones[dst.getId()].getTilesVector())
|
||||
{
|
||||
if(map.isPossible(ct))
|
||||
map.setOccupied(ct, ETileType::BLOCKED);
|
||||
@@ -155,7 +155,7 @@ RouteInfo WaterProxy::waterRoute(Zone & dst)
|
||||
}
|
||||
|
||||
//Don't place shipyard or boats on the very small lake
|
||||
if (lake.area.getTiles().size() < 25)
|
||||
if (lake.area.getTilesVector().size() < 25)
|
||||
{
|
||||
logGlobal->info("Skipping very small lake at zone %d", dst.getId());
|
||||
continue;
|
||||
@@ -273,7 +273,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, bool createRoad, Rout
|
||||
|
||||
while(!boardingPositions.empty())
|
||||
{
|
||||
auto boardingPosition = *boardingPositions.getTiles().begin();
|
||||
auto boardingPosition = *boardingPositions.getTilesVector().begin();
|
||||
rmg::Area shipPositions({boardingPosition});
|
||||
auto boutside = shipPositions.getBorderOutside();
|
||||
shipPositions.assign(boutside);
|
||||
@@ -336,7 +336,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, bool
|
||||
|
||||
while(!boardingPositions.empty())
|
||||
{
|
||||
auto boardingPosition = *boardingPositions.getTiles().begin();
|
||||
auto boardingPosition = *boardingPositions.getTilesVector().begin();
|
||||
rmg::Area shipPositions({boardingPosition});
|
||||
auto boutside = shipPositions.getBorderOutside();
|
||||
shipPositions.assign(boutside);
|
||||
|
Reference in New Issue
Block a user