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)
|
void toAbsolute(Tileset & tiles, const int3 & position)
|
||||||
{
|
{
|
||||||
Tileset temp;
|
std::vector vec(tiles.begin(), tiles.end());
|
||||||
for(const auto & tile : tiles)
|
tiles.clear();
|
||||||
|
std::transform(vec.begin(), vec.end(), vstd::set_inserter(tiles), [position](const int3 & tile)
|
||||||
{
|
{
|
||||||
temp.insert(tile + position);
|
return tile + position;
|
||||||
}
|
});
|
||||||
tiles = std::move(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void toRelative(Tileset & tiles, const int3 & position)
|
void toRelative(Tileset & tiles, const int3 & position)
|
||||||
@@ -161,6 +161,7 @@ const Tileset & Area::getBorder() const
|
|||||||
return dBorderCache;
|
return dBorderCache;
|
||||||
|
|
||||||
//compute border cache
|
//compute border cache
|
||||||
|
dBorderCache.reserve(dTiles.bucket_count());
|
||||||
for(const auto & t : dTiles)
|
for(const auto & t : dTiles)
|
||||||
{
|
{
|
||||||
for(auto & i : int3::getDirs())
|
for(auto & i : int3::getDirs())
|
||||||
@@ -182,6 +183,7 @@ const Tileset & Area::getBorderOutside() const
|
|||||||
return dBorderOutsideCache;
|
return dBorderOutsideCache;
|
||||||
|
|
||||||
//compute outside border cache
|
//compute outside border cache
|
||||||
|
dBorderOutsideCache.reserve(dBorderCache.bucket_count() * 2);
|
||||||
for(const auto & t : dTiles)
|
for(const auto & t : dTiles)
|
||||||
{
|
{
|
||||||
for(auto & i : int3::getDirs())
|
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 Area::getSubarea(const std::function<bool(const int3 &)> & filter) const
|
||||||
{
|
{
|
||||||
Area subset;
|
Area subset;
|
||||||
|
subset.dTiles.reserve(getTilesVector().size());
|
||||||
vstd::copy_if(getTilesVector(), vstd::set_inserter(subset.dTiles), filter);
|
vstd::copy_if(getTilesVector(), vstd::set_inserter(subset.dTiles), filter);
|
||||||
return subset;
|
return subset;
|
||||||
}
|
}
|
||||||
@@ -329,7 +332,8 @@ void Area::erase(const int3 & tile)
|
|||||||
void Area::unite(const Area & area)
|
void Area::unite(const Area & area)
|
||||||
{
|
{
|
||||||
invalidate();
|
invalidate();
|
||||||
auto & vec = area.getTilesVector();
|
const auto & vec = area.getTilesVector();
|
||||||
|
dTiles.reserve(dTiles.size() + vec.size());
|
||||||
dTiles.insert(vec.begin(), vec.end());
|
dTiles.insert(vec.begin(), vec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,6 +341,7 @@ void Area::intersect(const Area & area)
|
|||||||
{
|
{
|
||||||
invalidate();
|
invalidate();
|
||||||
Tileset result;
|
Tileset result;
|
||||||
|
result.reserve(std::max(dTiles.size(), area.getTilesVector().size()));
|
||||||
for(const auto & t : area.getTilesVector())
|
for(const auto & t : area.getTilesVector())
|
||||||
{
|
{
|
||||||
if(dTiles.count(t))
|
if(dTiles.count(t))
|
||||||
@@ -361,7 +366,6 @@ void Area::translate(const int3 & shift)
|
|||||||
|
|
||||||
if(dTilesVectorCache.empty())
|
if(dTilesVectorCache.empty())
|
||||||
{
|
{
|
||||||
getTiles();
|
|
||||||
getTilesVector();
|
getTilesVector();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,15 +400,22 @@ Area operator+ (const Area & l, const int3 & r)
|
|||||||
|
|
||||||
Area operator+ (const Area & l, const Area & r)
|
Area operator+ (const Area & l, const Area & r)
|
||||||
{
|
{
|
||||||
Area result(l);
|
Area result;
|
||||||
result.unite(r);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Area operator- (const Area & l, const Area & r)
|
Area operator- (const Area & l, const Area & r)
|
||||||
{
|
{
|
||||||
Area result(l);
|
Area result(l);
|
||||||
result.subtract(r);
|
for(const auto & t : r.getTilesVector())
|
||||||
|
{
|
||||||
|
result.dTiles.erase(t);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +428,7 @@ Area operator* (const Area & l, const Area & r)
|
|||||||
|
|
||||||
bool 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> 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) };
|
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>;
|
using DistanceMap = std::map<int3, int>;
|
||||||
void toAbsolute(Tileset & tiles, const int3 & position);
|
void toAbsolute(Tileset & tiles, const int3 & position);
|
||||||
void toRelative(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())
|
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.isVisitable() || dBlockedAreaCache.empty())
|
||||||
if (!dObject.isBlockedVisitable())
|
if (!dObject.isBlockedVisitable())
|
||||||
// Do no assume blocked tile is accessible
|
// Do not assume blocked tile is accessible
|
||||||
dBlockedAreaCache.add(dObject.visitablePos());
|
dBlockedAreaCache.add(dObject.visitablePos());
|
||||||
}
|
}
|
||||||
return dBlockedAreaCache;
|
return dBlockedAreaCache;
|
||||||
@@ -71,7 +72,8 @@ const rmg::Area & Object::Instance::getAccessibleArea() const
|
|||||||
{
|
{
|
||||||
auto neighbours = rmg::Area({getVisitablePosition()}).getBorderOutside();
|
auto neighbours = rmg::Area({getVisitablePosition()}).getBorderOutside();
|
||||||
rmg::Area visitable = rmg::Area(neighbours) - getBlockedArea();
|
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))
|
if(isVisitableFrom(from))
|
||||||
dAccessibleAreaCache.add(from);
|
dAccessibleAreaCache.add(from);
|
||||||
|
@@ -95,7 +95,7 @@ void ObjectManager::updateDistances(std::function<ui32(const int3 & tile)> dista
|
|||||||
{
|
{
|
||||||
RecursiveLock lock(externalAccessMutex);
|
RecursiveLock lock(externalAccessMutex);
|
||||||
tilesByDistance.clear();
|
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);
|
ui32 d = distanceFunction(tile);
|
||||||
map.setNearestObjectDistance(tile, std::min(static_cast<float>(d), map.getNearestObjectDistance(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
|
else
|
||||||
{
|
{
|
||||||
for(const auto & tile : searchArea.getTiles())
|
for(const auto & tile : searchArea.getTilesVector())
|
||||||
{
|
{
|
||||||
obj.setPosition(tile);
|
obj.setPosition(tile);
|
||||||
|
|
||||||
@@ -469,7 +469,8 @@ bool ObjectManager::createRequiredObjects()
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmg::Object rmgNearObject(*nearby.obj);
|
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());
|
possibleArea.intersect(zone.areaPossible());
|
||||||
if(possibleArea.empty())
|
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())
|
for(auto * instance : object.instances())
|
||||||
{
|
{
|
||||||
objectsVisitableArea.add(instance->getVisitablePosition());
|
objectsVisitableArea.add(instance->getVisitablePosition());
|
||||||
@@ -716,7 +718,7 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Prefer non-blocking tiles, if any
|
// Prefer non-blocking tiles, if any
|
||||||
const auto & entrableTiles = object.getEntrableArea().getTiles();
|
const auto & entrableTiles = object.getEntrableArea().getTilesVector();
|
||||||
int3 entrableTile(-1, -1, -1);
|
int3 entrableTile(-1, -1, -1);
|
||||||
if (entrableTiles.empty())
|
if (entrableTiles.empty())
|
||||||
{
|
{
|
||||||
|
@@ -51,7 +51,7 @@ void ObstaclePlacer::process()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
toBlock.clear();
|
toBlock.clear();
|
||||||
for (const auto& tile : zone.areaPossible().getTiles())
|
for (const auto& tile : zone.areaPossible().getTilesVector())
|
||||||
{
|
{
|
||||||
rmg::Area neighbors;
|
rmg::Area neighbors;
|
||||||
rmg::Area t;
|
rmg::Area t;
|
||||||
@@ -76,7 +76,7 @@ void ObstaclePlacer::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
zone.areaPossible().subtract(toBlock);
|
zone.areaPossible().subtract(toBlock);
|
||||||
for (const auto& tile : toBlock.getTiles())
|
for (const auto& tile : toBlock.getTilesVector())
|
||||||
{
|
{
|
||||||
map.setOccupied(tile, ETileType::BLOCKED);
|
map.setOccupied(tile, ETileType::BLOCKED);
|
||||||
}
|
}
|
||||||
|
@@ -791,7 +791,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
|||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
{
|
{
|
||||||
Zone::Lock lock(zone.areaMutex);
|
Zone::Lock lock(zone.areaMutex);
|
||||||
size = zone.getArea().getTiles().size();
|
size = zone.getArea().getTilesVector().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalDensity = 0;
|
int totalDensity = 0;
|
||||||
@@ -891,8 +891,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto & guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
const auto & guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
const auto areaToBlock = rmgObject.getAccessibleArea(true) - guardedArea;
|
||||||
areaToBlock.subtract(guardedArea);
|
|
||||||
|
|
||||||
if (zone.freePaths().overlap(areaToBlock) || manager.getVisitableArea().overlap(areaToBlock))
|
if (zone.freePaths().overlap(areaToBlock) || manager.getVisitableArea().overlap(areaToBlock))
|
||||||
return -1.f;
|
return -1.f;
|
||||||
@@ -914,8 +913,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
|
|||||||
{
|
{
|
||||||
guards.unite(rmgObject.instances().back()->getBlockedArea());
|
guards.unite(rmgObject.instances().back()->getBlockedArea());
|
||||||
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
auto areaToBlock = rmgObject.getAccessibleArea(true) - guardedArea;
|
||||||
areaToBlock.subtract(guardedArea);
|
|
||||||
treasureBlockArea.unite(areaToBlock);
|
treasureBlockArea.unite(areaToBlock);
|
||||||
}
|
}
|
||||||
zone.connectPath(path);
|
zone.connectPath(path);
|
||||||
|
@@ -112,7 +112,7 @@ void WaterProxy::collectLakes()
|
|||||||
for(const auto & t : lake.getBorderOutside())
|
for(const auto & t : lake.getBorderOutside())
|
||||||
if(map.isOnMap(t))
|
if(map.isOnMap(t))
|
||||||
lakes.back().neighbourZones[map.getZoneID(t)].add(t);
|
lakes.back().neighbourZones[map.getZoneID(t)].add(t);
|
||||||
for(const auto & t : lake.getTiles())
|
for(const auto & t : lake.getTilesVector())
|
||||||
lakeMap[t] = lakeId;
|
lakeMap[t] = lakeId;
|
||||||
|
|
||||||
//each lake must have at least one free tile
|
//each lake must have at least one free tile
|
||||||
@@ -143,7 +143,7 @@ RouteInfo WaterProxy::waterRoute(Zone & dst)
|
|||||||
{
|
{
|
||||||
if(!lake.keepConnections.count(dst.getId()))
|
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))
|
if(map.isPossible(ct))
|
||||||
map.setOccupied(ct, ETileType::BLOCKED);
|
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
|
//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());
|
logGlobal->info("Skipping very small lake at zone %d", dst.getId());
|
||||||
continue;
|
continue;
|
||||||
@@ -273,7 +273,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, bool createRoad, Rout
|
|||||||
|
|
||||||
while(!boardingPositions.empty())
|
while(!boardingPositions.empty())
|
||||||
{
|
{
|
||||||
auto boardingPosition = *boardingPositions.getTiles().begin();
|
auto boardingPosition = *boardingPositions.getTilesVector().begin();
|
||||||
rmg::Area shipPositions({boardingPosition});
|
rmg::Area shipPositions({boardingPosition});
|
||||||
auto boutside = shipPositions.getBorderOutside();
|
auto boutside = shipPositions.getBorderOutside();
|
||||||
shipPositions.assign(boutside);
|
shipPositions.assign(boutside);
|
||||||
@@ -336,7 +336,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, bool
|
|||||||
|
|
||||||
while(!boardingPositions.empty())
|
while(!boardingPositions.empty())
|
||||||
{
|
{
|
||||||
auto boardingPosition = *boardingPositions.getTiles().begin();
|
auto boardingPosition = *boardingPositions.getTilesVector().begin();
|
||||||
rmg::Area shipPositions({boardingPosition});
|
rmg::Area shipPositions({boardingPosition});
|
||||||
auto boutside = shipPositions.getBorderOutside();
|
auto boutside = shipPositions.getBorderOutside();
|
||||||
shipPositions.assign(boutside);
|
shipPositions.assign(boutside);
|
||||||
|
Reference in New Issue
Block a user