فهرست منبع

Add some debug logging, Fix one special case when updating terrain type, Improve visual look of updated terrain types

beegee1 10 سال پیش
والد
کامیت
dafaf86eef
8فایلهای تغییر یافته به همراه176 افزوده شده و 26 حذف شده
  1. 1 0
      .gitignore
  2. 33 2
      lib/GameConstants.cpp
  3. 5 1
      lib/GameConstants.h
  4. 88 14
      lib/mapping/CMapEditManager.cpp
  5. 9 0
      lib/mapping/CMapEditManager.h
  6. 36 9
      test/CMapEditManagerTest.cpp
  7. BIN
      test/TerrainViewTest.h3m
  8. 4 0
      test/terrainViewMappings.json

+ 1 - 0
.gitignore

@@ -27,3 +27,4 @@ ui_*.h
 /CPackConfig.cmake
 /CPackConfig.cmake
 /CPackSourceConfig.cmake
 /CPackSourceConfig.cmake
 build-*
 build-*
+CMakeLists.txt.user.*

+ 33 - 2
lib/GameConstants.cpp

@@ -88,10 +88,10 @@ CCreature * CreatureID::toCreature() const
 CSpell * SpellID::toSpell() const
 CSpell * SpellID::toSpell() const
 {
 {
 	if(num < 0 || num >= VLC->spellh->objects.size())
 	if(num < 0 || num >= VLC->spellh->objects.size())
-	{	
+	{
 		logGlobal->errorStream() << "Unable to get spell of invalid ID " << int(num);
 		logGlobal->errorStream() << "Unable to get spell of invalid ID " << int(num);
 		return nullptr;
 		return nullptr;
-	}		
+	}
 	return VLC->spellh->objects[*this];
 	return VLC->spellh->objects[*this];
 }
 }
 
 
@@ -129,3 +129,34 @@ std::ostream & operator<<(std::ostream & os, const Battle::ActionType actionType
 	if (it == actionTypeToString.end()) return os << "<Unknown type>";
 	if (it == actionTypeToString.end()) return os << "<Unknown type>";
 	else return os << it->second;
 	else return os << it->second;
 }
 }
+
+std::ostream & operator<<(std::ostream & os, const ETerrainType actionType)
+{
+	static const std::map<ETerrainType::EETerrainType, std::string> terrainTypeToString =
+	{
+	#define DEFINE_ELEMENT(element) {ETerrainType::element, #element}
+		DEFINE_ELEMENT(WRONG),
+		DEFINE_ELEMENT(BORDER),
+		DEFINE_ELEMENT(DIRT),
+		DEFINE_ELEMENT(SAND),
+		DEFINE_ELEMENT(GRASS),
+		DEFINE_ELEMENT(SNOW),
+		DEFINE_ELEMENT(SWAMP),
+		DEFINE_ELEMENT(ROUGH),
+		DEFINE_ELEMENT(SUBTERRANEAN),
+		DEFINE_ELEMENT(LAVA),
+		DEFINE_ELEMENT(WATER),
+		DEFINE_ELEMENT(ROCK)
+	};
+
+	auto it = terrainTypeToString.find(actionType.num);
+	if (it == terrainTypeToString.end()) return os << "<Unknown type>";
+	else return os << it->second;
+}
+
+std::string ETerrainType::toString() const
+{
+	std::stringstream ss;
+	ss << *this;
+	return ss.str();
+}

+ 5 - 1
lib/GameConstants.h

@@ -702,7 +702,7 @@ namespace Battle
 
 
 std::ostream & operator<<(std::ostream & os, const Battle::ActionType actionType);
 std::ostream & operator<<(std::ostream & os, const Battle::ActionType actionType);
 
 
-class ETerrainType
+class DLL_LINKAGE ETerrainType
 {
 {
 public:
 public:
 	enum EETerrainType
 	enum EETerrainType
@@ -717,8 +717,12 @@ public:
 	ID_LIKE_CLASS_COMMON(ETerrainType, EETerrainType)
 	ID_LIKE_CLASS_COMMON(ETerrainType, EETerrainType)
 
 
 	EETerrainType num;
 	EETerrainType num;
+
+	std::string toString() const;
 };
 };
 
 
+DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const ETerrainType actionType);
+
 ID_LIKE_OPERATORS_DECLS(ETerrainType, ETerrainType::EETerrainType)
 ID_LIKE_OPERATORS_DECLS(ETerrainType, ETerrainType::EETerrainType)
 
 
 
 

+ 88 - 14
lib/mapping/CMapEditManager.cpp

@@ -482,13 +482,15 @@ void CDrawTerrainOperation::updateTerrainTypes()
 	{
 	{
 		const auto & centerPos = *(positions.begin());
 		const auto & centerPos = *(positions.begin());
 		auto centerTile = map->getTile(centerPos);
 		auto centerTile = map->getTile(centerPos);
+		logGlobal->debugStream() << boost::format("Set terrain tile at pos '%s' to type '%s'") % centerPos % centerTile.terType;
 		auto tiles = getInvalidTiles(centerPos);
 		auto tiles = getInvalidTiles(centerPos);
 		auto updateTerrainType = [&](const int3 & pos, bool tileRequiresValidation)
 		auto updateTerrainType = [&](const int3 & pos, bool tileRequiresValidation)
 		{
 		{
 			map->getTile(pos).terType = centerTile.terType;
 			map->getTile(pos).terType = centerTile.terType;
 			if(tileRequiresValidation) positions.insert(pos);
 			if(tileRequiresValidation) positions.insert(pos);
 			invalidateTerrainViews(pos);
 			invalidateTerrainViews(pos);
-			logGlobal->debugStream() << boost::format("Update terrain tile at '%s' to type '%i'.") % pos % centerTile.terType;
+			logGlobal->debugStream() << boost::format("Set additional terrain tile at pos '%s' to type '%s'; tileRequiresValidation '%s'") % pos
+				% centerTile.terType % tileRequiresValidation;
 		};
 		};
 
 
 		// Fill foreign invalid tiles
 		// Fill foreign invalid tiles
@@ -497,12 +499,14 @@ void CDrawTerrainOperation::updateTerrainTypes()
 			updateTerrainType(tile, true);
 			updateTerrainType(tile, true);
 		}
 		}
 
 
+		tiles = getInvalidTiles(centerPos);
 		if(tiles.nativeTiles.find(centerPos) != tiles.nativeTiles.end())
 		if(tiles.nativeTiles.find(centerPos) != tiles.nativeTiles.end())
 		{
 		{
 			// Blow up
 			// Blow up
 			auto rect = extendTileAroundSafely(centerPos);
 			auto rect = extendTileAroundSafely(centerPos);
 			std::set<int3> suitableTiles;
 			std::set<int3> suitableTiles;
 			int invalidForeignTilesCnt = std::numeric_limits<int>::max(), invalidNativeTilesCnt = 0;
 			int invalidForeignTilesCnt = std::numeric_limits<int>::max(), invalidNativeTilesCnt = 0;
+			bool centerPosValid = false;
 			rect.forEach([&](const int3 & posToTest)
 			rect.forEach([&](const int3 & posToTest)
 			{
 			{
 				auto & terrainTile = map->getTile(posToTest);
 				auto & terrainTile = map->getTile(posToTest);
@@ -511,28 +515,64 @@ void CDrawTerrainOperation::updateTerrainTypes()
 					auto formerTerType = terrainTile.terType;
 					auto formerTerType = terrainTile.terType;
 					terrainTile.terType = centerTile.terType;
 					terrainTile.terType = centerTile.terType;
 					auto testTile = getInvalidTiles(posToTest);
 					auto testTile = getInvalidTiles(posToTest);
-					auto addToSuitableTiles = [&](const int3 & pos)
-					{
-						suitableTiles.insert(pos);
-						logGlobal->debugStream() << boost::format(std::string("Found suitable tile '%s' for main tile '%s': ") +
-								"Invalid native tiles '%i', invalid foreign tiles '%i'.") % pos % centerPos % testTile.nativeTiles.size() %
-								testTile.foreignTiles.size();
-					};
 
 
 					int nativeTilesCntNorm = testTile.nativeTiles.empty() ? std::numeric_limits<int>::max() : testTile.nativeTiles.size();
 					int nativeTilesCntNorm = testTile.nativeTiles.empty() ? std::numeric_limits<int>::max() : testTile.nativeTiles.size();
-					if(nativeTilesCntNorm > invalidNativeTilesCnt ||
-							(nativeTilesCntNorm == invalidNativeTilesCnt && testTile.foreignTiles.size() < invalidForeignTilesCnt))
+
+					bool putSuitableTile = false;
+					bool addToSuitableTiles = false;
+					if(testTile.centerPosValid)
+					{
+						if (!centerPosValid)
+						{
+							centerPosValid = true;
+							putSuitableTile = true;
+						}
+						else
+						{
+							if(testTile.foreignTiles.size() < invalidForeignTilesCnt)
+							{
+								putSuitableTile = true;
+							}
+							else
+							{
+								addToSuitableTiles = true;
+							}
+						}
+					}
+					else if (!centerPosValid)
 					{
 					{
+						if((nativeTilesCntNorm > invalidNativeTilesCnt) ||
+								(nativeTilesCntNorm == invalidNativeTilesCnt && testTile.foreignTiles.size() < invalidForeignTilesCnt))
+						{
+							putSuitableTile = true;
+						}
+						else if(nativeTilesCntNorm == invalidNativeTilesCnt && testTile.foreignTiles.size() == invalidForeignTilesCnt)
+						{
+							addToSuitableTiles = true;
+						}
+					}
+
+					if (putSuitableTile)
+					{
+						if(!suitableTiles.empty())
+						{
+							logGlobal->debugStream() << "Clear suitables tiles.";
+						}
+
 						invalidNativeTilesCnt = nativeTilesCntNorm;
 						invalidNativeTilesCnt = nativeTilesCntNorm;
 						invalidForeignTilesCnt = testTile.foreignTiles.size();
 						invalidForeignTilesCnt = testTile.foreignTiles.size();
 						suitableTiles.clear();
 						suitableTiles.clear();
-						addToSuitableTiles(posToTest);
+						addToSuitableTiles = true;
 					}
 					}
-					else if(nativeTilesCntNorm == invalidNativeTilesCnt &&
-							testTile.foreignTiles.size() == invalidForeignTilesCnt)
+
+					if (addToSuitableTiles)
 					{
 					{
-						addToSuitableTiles(posToTest);
+						suitableTiles.insert(posToTest);
+						logGlobal->debugStream() << boost::format(std::string("Found suitable tile '%s' for main tile '%s': ") +
+								"Invalid native tiles '%i', invalid foreign tiles '%i', centerPosValid '%i'") % posToTest % centerPos % testTile.nativeTiles.size() %
+								testTile.foreignTiles.size() % testTile.centerPosValid;
 					}
 					}
+
 					terrainTile.terType = formerTerType;
 					terrainTile.terType = formerTerType;
 				}
 				}
 			});
 			});
@@ -591,6 +631,7 @@ void CDrawTerrainOperation::updateTerrainViews()
 		{
 		{
 			// This shouldn't be the case
 			// This shouldn't be the case
 			logGlobal->warnStream() << boost::format("No pattern detected at pos '%s'.") % pos;
 			logGlobal->warnStream() << boost::format("No pattern detected at pos '%s'.") % pos;
+			CTerrainViewPatternUtils::printDebuggingInfoAboutTile(map, pos);
 			continue;
 			continue;
 		}
 		}
 
 
@@ -878,6 +919,10 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 				if(terType == centerTerType) tiles.nativeTiles.insert(pos);
 				if(terType == centerTerType) tiles.nativeTiles.insert(pos);
 				else tiles.foreignTiles.insert(pos);
 				else tiles.foreignTiles.insert(pos);
 			}
 			}
+			else if(centerPos == pos)
+			{
+				tiles.centerPosValid = true;
+			}
 		}
 		}
 	});
 	});
 	return tiles;
 	return tiles;
@@ -899,6 +944,35 @@ CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, const std
 
 
 }
 }
 
 
+void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int3 pos)
+{
+	logGlobal->debugStream() << "Printing detailed info about nearby map tiles of pos '" << pos << "'";
+	for(int y = pos.y - 2; y <= pos.y + 2; ++y)
+	{
+		std::string line;
+		const int PADDED_LENGTH = 10;
+		for(int x = pos.x - 2; x <= pos.x + 2; ++x)
+		{
+			auto debugPos = int3(x, y, pos.z);
+			if(map->isInTheMap(debugPos))
+			{
+				auto debugTile = map->getTile(debugPos);
+
+				std::string terType = debugTile.terType.toString().substr(0, 6);
+				line += terType;
+				line.insert(line.end(), PADDED_LENGTH - terType.size(), ' ');
+			}
+			else
+			{
+				line += "X";
+				line.insert(line.end(), PADDED_LENGTH - 1, ' ');
+			}
+		}
+
+		logGlobal->debugStream() << line;
+	}
+}
+
 CClearTerrainOperation::CClearTerrainOperation(CMap * map, CRandomGenerator * gen) : CComposedOperation(map)
 CClearTerrainOperation::CClearTerrainOperation(CMap * map, CRandomGenerator * gen) : CComposedOperation(map)
 {
 {
 	CTerrainSelection terrainSel(map);
 	CTerrainSelection terrainSel(map);

+ 9 - 0
lib/mapping/CMapEditManager.h

@@ -318,6 +318,9 @@ private:
 	struct InvalidTiles
 	struct InvalidTiles
 	{
 	{
 		std::set<int3> foreignTiles, nativeTiles;
 		std::set<int3> foreignTiles, nativeTiles;
+		bool centerPosValid;
+
+		InvalidTiles() : centerPosValid(false) { }
 	};
 	};
 
 
 	void updateTerrainTypes();
 	void updateTerrainTypes();
@@ -346,6 +349,12 @@ private:
 	std::set<int3> invalidatedTerViews;
 	std::set<int3> invalidatedTerViews;
 };
 };
 
 
+class DLL_LINKAGE CTerrainViewPatternUtils
+{
+public:
+	static void printDebuggingInfoAboutTile(const CMap * map, int3 pos);
+};
+
 /// The CClearTerrainOperation clears+initializes the terrain.
 /// The CClearTerrainOperation clears+initializes the terrain.
 class CClearTerrainOperation : public CComposedOperation
 class CClearTerrainOperation : public CComposedOperation
 {
 {

+ 36 - 9
test/CMapEditManagerTest.cpp

@@ -71,6 +71,32 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_Type)
 		}
 		}
 		editManager->drawTerrain(ETerrainType::GRASS);
 		editManager->drawTerrain(ETerrainType::GRASS);
 		BOOST_CHECK(map->getTile(int3(35, 44, 0)).terType == ETerrainType::WATER);
 		BOOST_CHECK(map->getTile(int3(35, 44, 0)).terType == ETerrainType::WATER);
+
+		// Rock case
+		editManager->getTerrainSelection().selectRange(MapRect(int3(1, 1, 1), 15, 15));
+		editManager->drawTerrain(ETerrainType::SUBTERRANEAN);
+		std::vector<int3> vec({ int3(6, 6, 1), int3(7, 6, 1), int3(8, 6, 1), int3(5, 7, 1), int3(6, 7, 1), int3(7, 7, 1),
+								int3(8, 7, 1), int3(4, 8, 1), int3(5, 8, 1), int3(6, 8, 1)});
+		editManager->getTerrainSelection().setSelection(vec);
+		editManager->drawTerrain(ETerrainType::ROCK);
+		BOOST_CHECK(map->getTile(int3(5, 6, 1)).terType == ETerrainType::ROCK || map->getTile(int3(7, 8, 1)).terType == ETerrainType::ROCK);
+
+		// next check
+		auto map2 = make_unique<CMap>();
+		map2->width = 128;
+		map2->height = 128;
+		map2->initTerrain();
+		auto editManager2 = map2->getEditManager();
+
+		editManager2->getTerrainSelection().selectRange(MapRect(int3(0, 0, 1), 128, 128));
+		editManager2->drawTerrain(ETerrainType::SUBTERRANEAN);
+
+		std::vector<int3> selection({ int3(95, 43, 1), int3(95, 44, 1), int3(94, 45, 1), int3(95, 45, 1), int3(96, 45, 1),
+									int3(93, 46, 1), int3(94, 46, 1), int3(95, 46, 1), int3(96, 46, 1), int3(97, 46, 1),
+									int3(98, 46, 1), int3(99, 46, 1)});
+		editManager2->getTerrainSelection().setSelection(selection);
+		editManager2->drawTerrain(ETerrainType::ROCK);
+
 	}
 	}
 	catch(const std::exception & e)
 	catch(const std::exception & e)
 	{
 	{
@@ -82,15 +108,15 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_View)
 {
 {
 	try
 	try
 	{
 	{
-		// Load maps and json config
-		
-		#if defined(__MINGW32__)
-		const std::string TEST_DATA_DIR = "test/"; 
-		#else
-		const std::string TEST_DATA_DIR = "."; 
-		#endif // defined
-		
-		
+		// Load maps and json config
+
+		#if defined(__MINGW32__)
+		const std::string TEST_DATA_DIR = "test/";
+		#else
+		const std::string TEST_DATA_DIR = ".";
+		#endif // defined
+
+
 		auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
 		auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
 		dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
 		dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
 		const auto originalMap = CMapService::loadMap("test/TerrainViewTest");
 		const auto originalMap = CMapService::loadMap("test/TerrainViewTest");
@@ -124,6 +150,7 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_View)
 				if(posVector.size() != 3) throw std::runtime_error("A position should consist of three values x,y,z. Continue with next position.");
 				if(posVector.size() != 3) throw std::runtime_error("A position should consist of three values x,y,z. Continue with next position.");
 				int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float());
 				int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float());
 				logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z;
 				logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z;
+				CTerrainViewPatternUtils::printDebuggingInfoAboutTile(map.get(), pos);
 				const auto & originalTile = originalMap->getTile(pos);
 				const auto & originalTile = originalMap->getTile(pos);
 				editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
 				editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
 				editManager->drawTerrain(originalTile.terType, &gen);
 				editManager->drawTerrain(originalTile.terType, &gen);

BIN
test/TerrainViewTest.h3m


+ 4 - 0
test/terrainViewMappings.json

@@ -165,6 +165,10 @@
 			"pos" : [ [ 12,24,1 ] ],
 			"pos" : [ [ 12,24,1 ] ],
 			"pattern" : "rock.s5"
 			"pattern" : "rock.s5"
 		},
 		},
+		{
+			"pos" : [ [ 16,4,1 ] ],
+			"pattern" : "rock.s5"
+		},
 		{
 		{
 			"pos" : [ [ 8,23,1 ] ],
 			"pos" : [ [ 8,23,1 ] ],
 			"pattern" : "rock.s6"
 			"pattern" : "rock.s6"