Browse Source

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

beegee1 10 years ago
parent
commit
dafaf86eef

+ 1 - 0
.gitignore

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

+ 33 - 2
lib/GameConstants.cpp

@@ -88,10 +88,10 @@ CCreature * CreatureID::toCreature() const
 CSpell * SpellID::toSpell() const
 {
 	if(num < 0 || num >= VLC->spellh->objects.size())
-	{	
+	{
 		logGlobal->errorStream() << "Unable to get spell of invalid ID " << int(num);
 		return nullptr;
-	}		
+	}
 	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>";
 	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);
 
-class ETerrainType
+class DLL_LINKAGE ETerrainType
 {
 public:
 	enum EETerrainType
@@ -717,8 +717,12 @@ public:
 	ID_LIKE_CLASS_COMMON(ETerrainType, EETerrainType)
 
 	EETerrainType num;
+
+	std::string toString() const;
 };
 
+DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const ETerrainType actionType);
+
 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());
 		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 updateTerrainType = [&](const int3 & pos, bool tileRequiresValidation)
 		{
 			map->getTile(pos).terType = centerTile.terType;
 			if(tileRequiresValidation) positions.insert(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
@@ -497,12 +499,14 @@ void CDrawTerrainOperation::updateTerrainTypes()
 			updateTerrainType(tile, true);
 		}
 
+		tiles = getInvalidTiles(centerPos);
 		if(tiles.nativeTiles.find(centerPos) != tiles.nativeTiles.end())
 		{
 			// Blow up
 			auto rect = extendTileAroundSafely(centerPos);
 			std::set<int3> suitableTiles;
 			int invalidForeignTilesCnt = std::numeric_limits<int>::max(), invalidNativeTilesCnt = 0;
+			bool centerPosValid = false;
 			rect.forEach([&](const int3 & posToTest)
 			{
 				auto & terrainTile = map->getTile(posToTest);
@@ -511,28 +515,64 @@ void CDrawTerrainOperation::updateTerrainTypes()
 					auto formerTerType = terrainTile.terType;
 					terrainTile.terType = centerTile.terType;
 					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();
-					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;
 						invalidForeignTilesCnt = testTile.foreignTiles.size();
 						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;
 				}
 			});
@@ -591,6 +631,7 @@ void CDrawTerrainOperation::updateTerrainViews()
 		{
 			// This shouldn't be the case
 			logGlobal->warnStream() << boost::format("No pattern detected at pos '%s'.") % pos;
+			CTerrainViewPatternUtils::printDebuggingInfoAboutTile(map, pos);
 			continue;
 		}
 
@@ -878,6 +919,10 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 				if(terType == centerTerType) tiles.nativeTiles.insert(pos);
 				else tiles.foreignTiles.insert(pos);
 			}
+			else if(centerPos == pos)
+			{
+				tiles.centerPosValid = true;
+			}
 		}
 	});
 	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)
 {
 	CTerrainSelection terrainSel(map);

+ 9 - 0
lib/mapping/CMapEditManager.h

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

+ 36 - 9
test/CMapEditManagerTest.cpp

@@ -71,6 +71,32 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_Type)
 		}
 		editManager->drawTerrain(ETerrainType::GRASS);
 		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)
 	{
@@ -82,15 +108,15 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_View)
 {
 	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);
 		dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
 		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.");
 				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;
+				CTerrainViewPatternUtils::printDebuggingInfoAboutTile(map.get(), pos);
 				const auto & originalTile = originalMap->getTile(pos);
 				editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
 				editManager->drawTerrain(originalTile.terType, &gen);

BIN
test/TerrainViewTest.h3m


+ 4 - 0
test/terrainViewMappings.json

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