mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Add some debug logging, Fix one special case when updating terrain type, Improve visual look of updated terrain types
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -27,3 +27,4 @@ ui_*.h | ||||
| /CPackConfig.cmake | ||||
| /CPackSourceConfig.cmake | ||||
| build-* | ||||
| CMakeLists.txt.user.* | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
| { | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -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" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user