Explorar o código

Huge optimization based on profiling - cut generation time by almost half (Jebus XL+U).

DjWarmonger %!s(int64=9) %!d(string=hai) anos
pai
achega
7f0b852449
Modificáronse 4 ficheiros con 43 adicións e 14 borrados
  1. 16 0
      lib/rmg/CMapGenerator.cpp
  2. 4 0
      lib/rmg/CMapGenerator.h
  3. 20 13
      lib/rmg/CRmgTemplateZone.cpp
  4. 3 1
      lib/rmg/CZonePlacer.cpp

+ 16 - 0
lib/rmg/CMapGenerator.cpp

@@ -60,6 +60,8 @@ void CMapGenerator::initTiles()
 			tiles[i][j] = new CTileInfo[level];
 		}
 	}
+
+	zoneColouring.resize(boost::extents[map->twoLevel ? 2 : 1][map->width][map->height]);
 }
 
 CMapGenerator::~CMapGenerator()
@@ -697,6 +699,20 @@ CTileInfo CMapGenerator::getTile(const int3& tile) const
 	return tiles[tile.x][tile.y][tile.z];
 }
 
+TRmgTemplateZoneId CMapGenerator::getZoneID(const int3& tile) const
+{
+	checkIsOnMap(tile);
+
+	return zoneColouring[tile.z][tile.x][tile.y];
+}
+
+void CMapGenerator::setZoneID(const int3& tile, TRmgTemplateZoneId zid) 
+{
+	checkIsOnMap(tile);
+
+	zoneColouring[tile.z][tile.x][tile.y] = zid;
+}
+
 bool CMapGenerator::isAllowedSpell(SpellID sid) const
 {
 	assert(sid >= 0);

+ 4 - 0
lib/rmg/CMapGenerator.h

@@ -94,12 +94,16 @@ public:
 	ui32 getZoneCount(TFaction faction);
 	ui32 getTotalZoneCount() const;
 
+	TRmgTemplateZoneId getZoneID(const int3& tile) const;
+	void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
+
 private:
 	std::map<TRmgTemplateZoneId, CRmgTemplateZone*> zones;
 	std::map<TFaction, ui32> zonesPerFaction;
 	ui32 zonesTotal; //zones that have their main town only
 
 	CTileInfo*** tiles;
+	boost::multi_array<TRmgTemplateZoneId, 3> zoneColouring; //[z][x][y]
 
 	int prisonsRemaining;
 	//int questArtsRemaining;

+ 20 - 13
lib/rmg/CRmgTemplateZone.cpp

@@ -430,15 +430,21 @@ void CRmgTemplateZone::createBorder(CMapGenerator* gen)
 {
 	for (auto tile : tileinfo)
 	{
-		gen->foreach_neighbour (tile, [this, gen](int3 &pos)
+		bool edge = false;
+		gen->foreach_neighbour(tile, [this, gen, &edge](int3 &pos)
 		{
-			if (!vstd::contains(this->tileinfo, pos))
+			if (edge)
+				return; //optimization - do it only once
+			if (gen->getZoneID(pos) != id) //optimization - better than set search
 			{
-				gen->foreach_neighbour (pos, [this, gen](int3 &pos)
+				//we are edge if at least one tile does not belong to zone
+				//mark all nearby tiles blocked and we're done
+				gen->foreach_neighbour (pos, [this, gen](int3 &nearbyPos)
 				{
-					if (gen->isPossible(pos))
-						gen->setOccupied (pos, ETileType::BLOCKED);
+					if (gen->isPossible(nearbyPos))
+						gen->setOccupied(nearbyPos, ETileType::BLOCKED);
 				});
+				edge = true; 
 			}
 		});
 	}
@@ -663,7 +669,7 @@ do not leave zone border
 				{
 					if (!gen->isBlocked(pos))
 					{
-						if (vstd::contains (tileinfo, pos))
+						if (gen->getZoneID(pos) == id)
 						{
 							if (gen->isPossible(pos))
 							{
@@ -700,7 +706,7 @@ do not leave zone border
 			{
 				if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles
 				{
-					if (vstd::contains(tileinfo, pos))
+					if (gen->getZoneID(pos) == id)
 					{
 						if (gen->isPossible(pos))
 						{
@@ -799,7 +805,7 @@ bool CRmgTemplateZone::createRoad(CMapGenerator* gen, const int3& src, const int
 					//if (gen->map->checkForVisitableDir(currentNode, &gen->map->getTile(pos), pos)) //TODO: why it has no effect?
 					if (gen->isFree(pos) || pos == dst || (obj && obj->ID == Obj::MONSTER))
 					{
-						if (vstd::contains(this->tileinfo, pos) || pos == dst) //otherwise guard position may appear already connected to other zone.
+						if (gen->getZoneID(pos) == id || pos == dst) //otherwise guard position may appear already connected to other zone.
 						{
 							cameFrom[pos] = currentNode;
 							open.insert(pos);
@@ -867,18 +873,19 @@ bool CRmgTemplateZone::connectPath(CMapGenerator* gen, const int3& src, bool onl
 		{
 			auto foo = [gen, this, &open, &closed, &cameFrom, &currentNode, &distances](int3& pos) -> void
 			{
+				if (gen->isBlocked(pos)) //no paths through blocked or occupied tiles
+					return;
+
 				int distance = distances[currentNode] + 1;
 				int bestDistanceSoFar = 1e6; //FIXME: boost::limits
 				auto it = distances.find(pos);
 				if (it != distances.end())
 					bestDistanceSoFar = it->second;
 
-				if (gen->isBlocked(pos)) //no paths through blocked or occupied tiles
-					return;
 				if (distance < bestDistanceSoFar || !vstd::contains(closed, pos))
 				{
 					//auto obj = gen->map->getTile(pos).topVisitableObj();
-					if (vstd::contains(this->tileinfo, pos))
+					if (gen->getZoneID(pos) == id)
 					{
 						cameFrom[pos] = currentNode;
 						open.insert(pos);
@@ -962,7 +969,7 @@ bool CRmgTemplateZone::connectWithCenter(CMapGenerator* gen, const int3& src, bo
 				if (distance < bestDistanceSoFar || !vstd::contains(closed, pos))
 				{
 					//auto obj = gen->map->getTile(pos).topVisitableObj();
-					if (vstd::contains(this->tileinfo, pos))
+					if (gen->getZoneID(pos) == id)
 					{
 						cameFrom[pos] = currentNode;
 						open.insert(pos);
@@ -1879,7 +1886,7 @@ void CRmgTemplateZone::drawRoads(CMapGenerator* gen)
 	}
 	for (auto tile : roadNodes)
 	{
-		if (vstd::contains(tileinfo, tile)) //mark roads for our nodes, but not for zone guards in other zones
+		if (gen->getZoneID(tile) == id) //mark roads for our nodes, but not for zone guards in other zones
 			tiles.push_back(tile);
 	}
 

+ 3 - 1
lib/rmg/CZonePlacer.cpp

@@ -541,7 +541,9 @@ void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
 					else
 						distances.push_back (std::make_pair(zone.second, std::numeric_limits<float>::max()));
 				}
-				boost::min_element(distances, compareByDistance)->first->addTile(pos); //closest tile belongs to zone
+				auto zone = boost::min_element(distances, compareByDistance)->first; //closest tile belongs to zone
+				zone->addTile(pos);
+				gen->setZoneID(pos, zone->getId());
 			}
 		}
 	}