From 19e851ddffaca0673617a62810186cfd9fb301fa Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 22 Dec 2023 17:41:30 +0200 Subject: [PATCH 1/4] Implemented configurable level of decorations for terrains --- config/terrainViewPatterns.json | 3 ++- lib/mapping/CMapEditManager.cpp | 6 ++---- lib/mapping/CMapEditManager.h | 2 +- lib/mapping/CMapOperation.cpp | 22 ++++++++++++++-------- lib/mapping/CMapOperation.h | 3 ++- lib/mapping/MapEditUtils.cpp | 2 ++ lib/mapping/MapEditUtils.h | 2 ++ lib/rmg/RmgMap.cpp | 7 ++++++- lib/rmg/RmgMap.h | 2 ++ lib/rmg/threadpool/MapProxy.cpp | 4 ++-- lib/rmg/threadpool/MapProxy.h | 4 ++-- 11 files changed, 37 insertions(+), 20 deletions(-) diff --git a/config/terrainViewPatterns.json b/config/terrainViewPatterns.json index 571227ccf..783edd3c2 100644 --- a/config/terrainViewPatterns.json +++ b/config/terrainViewPatterns.json @@ -85,7 +85,8 @@ "N", "N", "N", "N", "N", "N" ], - "mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7", "hota" : "77-117" } + "decoration" : true, + "mapping" : { "normal" : "49-56,57-72", "dirt" : "21-28,29-44", "sand" : "0-11,12-23", "water" : "20-32", "rock": "0-7", "hota" : "77-101,102-117" } }, // Mixed transitions { diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index fcc4cdaf9..5a8a1c996 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -125,9 +125,9 @@ void CMapEditManager::clearTerrain(CRandomGenerator * gen) execute(std::make_unique(map, gen ? gen : &(this->gen))); } -void CMapEditManager::drawTerrain(TerrainId terType, CRandomGenerator * gen) +void CMapEditManager::drawTerrain(TerrainId terType, int decorationsPercentage, CRandomGenerator * gen) { - execute(std::make_unique(map, terrainSel, terType, gen ? gen : &(this->gen))); + execute(std::make_unique(map, terrainSel, terType, decorationsPercentage, gen ? gen : &(this->gen))); terrainSel.clearSelection(); } @@ -143,8 +143,6 @@ void CMapEditManager::drawRiver(RiverId riverType, CRandomGenerator* gen) terrainSel.clearSelection(); } - - void CMapEditManager::insertObject(CGObjectInstance * obj) { execute(std::make_unique(map, obj)); diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index 4daf3c398..e380db826 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -70,7 +70,7 @@ public: void clearTerrain(CRandomGenerator * gen = nullptr); /// Draws terrain at the current terrain selection. The selection will be cleared automatically. - void drawTerrain(TerrainId terType, CRandomGenerator * gen = nullptr); + void drawTerrain(TerrainId terType, int decorationsPercentage, CRandomGenerator * gen = nullptr); /// Draws roads at the current terrain selection. The selection will be cleared automatically. void drawRoad(RoadId roadType, CRandomGenerator * gen = nullptr); diff --git a/lib/mapping/CMapOperation.cpp b/lib/mapping/CMapOperation.cpp index 1865523ba..bb5ce4d7b 100644 --- a/lib/mapping/CMapOperation.cpp +++ b/lib/mapping/CMapOperation.cpp @@ -83,10 +83,11 @@ void CComposedOperation::addOperation(std::unique_ptr&& operation operations.push_back(std::move(operation)); } -CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, CRandomGenerator * gen): +CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, int decorationsPercentage, CRandomGenerator * gen): CMapOperation(map), terrainSel(std::move(terrainSel)), terType(terType), + decorationsPercentage(decorationsPercentage), gen(gen) { @@ -286,14 +287,19 @@ void CDrawTerrainOperation::updateTerrainViews() // Get mapping const TerrainViewPattern& pattern = patterns[bestPattern][valRslt.flip]; std::pair mapping; - if(valRslt.transitionReplacement.empty()) + + mapping = pattern.mapping[0]; + + if(pattern.decoration) { - mapping = pattern.mapping[0]; + if (gen->nextInt(100) > decorationsPercentage) + mapping = pattern.mapping[0]; + else + mapping = pattern.mapping[1]; } - else - { + + if (!valRslt.transitionReplacement.empty()) mapping = valRslt.transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1]; - } // Set terrain view auto & tile = map->getTile(pos); @@ -555,12 +561,12 @@ CClearTerrainOperation::CClearTerrainOperation(CMap* map, CRandomGenerator* gen) { CTerrainSelection terrainSel(map); terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height)); - addOperation(std::make_unique(map, terrainSel, ETerrainId::WATER, gen)); + addOperation(std::make_unique(map, terrainSel, ETerrainId::WATER, 0, gen)); if(map->twoLevel) { terrainSel.clearSelection(); terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height)); - addOperation(std::make_unique(map, terrainSel, ETerrainId::ROCK, gen)); + addOperation(std::make_unique(map, terrainSel, ETerrainId::ROCK, 0, gen)); } } diff --git a/lib/mapping/CMapOperation.h b/lib/mapping/CMapOperation.h index 688a99edb..0ac59c101 100644 --- a/lib/mapping/CMapOperation.h +++ b/lib/mapping/CMapOperation.h @@ -63,7 +63,7 @@ private: class CDrawTerrainOperation : public CMapOperation { public: - CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, CRandomGenerator * gen); + CDrawTerrainOperation(CMap * map, CTerrainSelection terrainSel, TerrainId terType, int decorationsPercentage, CRandomGenerator * gen); void execute() override; void undo() override; @@ -101,6 +101,7 @@ private: CTerrainSelection terrainSel; TerrainId terType; + int decorationsPercentage; CRandomGenerator* gen; std::set invalidatedTerViews; }; diff --git a/lib/mapping/MapEditUtils.cpp b/lib/mapping/MapEditUtils.cpp index eef87e147..8d9e6a2d7 100644 --- a/lib/mapping/MapEditUtils.cpp +++ b/lib/mapping/MapEditUtils.cpp @@ -145,6 +145,7 @@ const std::string TerrainViewPattern::RULE_ANY = "?"; TerrainViewPattern::TerrainViewPattern() : diffImages(false) , rotationTypesCount(0) + , decoration(false) , minPoints(0) , maxPoints(std::numeric_limits::max()) { @@ -209,6 +210,7 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() // Read various properties pattern.id = ptrnNode["id"].String(); assert(!pattern.id.empty()); + pattern.decoration = ptrnNode["decoration"].Bool(); pattern.minPoints = static_cast(ptrnNode["minPoints"].Float()); pattern.maxPoints = static_cast(ptrnNode["maxPoints"].Float()); if (pattern.maxPoints == 0) diff --git a/lib/mapping/MapEditUtils.h b/lib/mapping/MapEditUtils.h index d7385362b..ebb0bea5c 100644 --- a/lib/mapping/MapEditUtils.h +++ b/lib/mapping/MapEditUtils.h @@ -199,6 +199,8 @@ struct DLL_LINKAGE TerrainViewPattern /// If diffImages is true, different images/frames are used to place a rotated terrain view. If it's false /// the same frame will be used and rotated. bool diffImages; + /// If true, then this pattern describes decoration tiles and should be used with specified probability + bool decoration; /// The rotationTypesCount is only used if diffImages is true and holds the number how many rotation types(horizontal, etc...) /// are supported. int rotationTypesCount; diff --git a/lib/rmg/RmgMap.cpp b/lib/rmg/RmgMap.cpp index cdf8e0bb0..e192d3918 100644 --- a/lib/rmg/RmgMap.cpp +++ b/lib/rmg/RmgMap.cpp @@ -45,6 +45,11 @@ RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) : getEditManager()->getUndoManager().setUndoRedoLimit(0); } +int RmgMap::getDecorationsPercentage() const +{ + return 10; // arbitrary value to generate more readable map +} + void RmgMap::foreach_neighbour(const int3 & pos, const std::function & foo) const { for(const int3 &dir : int3::getDirs()) @@ -90,7 +95,7 @@ void RmgMap::initTiles(CMapGenerator & generator, CRandomGenerator & rand) getEditManager()->clearTerrain(&rand); getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight())); - getEditManager()->drawTerrain(ETerrainId::GRASS, &rand); + getEditManager()->drawTerrain(ETerrainId::GRASS, getDecorationsPercentage(), &rand); const auto * tmpl = mapGenOptions.getMapTemplate(); zones.clear(); diff --git a/lib/rmg/RmgMap.h b/lib/rmg/RmgMap.h index 11213d031..c02f171f0 100644 --- a/lib/rmg/RmgMap.h +++ b/lib/rmg/RmgMap.h @@ -27,6 +27,8 @@ class playerInfo; class RmgMap { public: + int getDecorationsPercentage() const; + mutable std::unique_ptr mapInstance; std::shared_ptr getMapProxy() const; CMap & getMap(const CMapGenerator *) const; //limited access diff --git a/lib/rmg/threadpool/MapProxy.cpp b/lib/rmg/threadpool/MapProxy.cpp index d1bf2f8ee..da1ce88e9 100644 --- a/lib/rmg/threadpool/MapProxy.cpp +++ b/lib/rmg/threadpool/MapProxy.cpp @@ -40,7 +40,7 @@ void MapProxy::drawTerrain(CRandomGenerator & generator, std::vector & til { Lock lock(mx); map.getEditManager()->getTerrainSelection().setSelection(tiles); - map.getEditManager()->drawTerrain(terrain, &generator); + map.getEditManager()->drawTerrain(terrain, map.getDecorationsPercentage(), &generator); } void MapProxy::drawRivers(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain) @@ -57,4 +57,4 @@ void MapProxy::drawRoads(CRandomGenerator & generator, std::vector & tiles map.getEditManager()->drawRoad(roadType, &generator); } -VCMI_LIB_NAMESPACE_END \ No newline at end of file +VCMI_LIB_NAMESPACE_END diff --git a/lib/rmg/threadpool/MapProxy.h b/lib/rmg/threadpool/MapProxy.h index a85d74fbf..bf74e88e7 100644 --- a/lib/rmg/threadpool/MapProxy.h +++ b/lib/rmg/threadpool/MapProxy.h @@ -28,7 +28,7 @@ public: void insertObjects(std::set& objects); void removeObject(CGObjectInstance* obj); - void drawTerrain(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); + void drawTerrain(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); void drawRivers(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); void drawRoads(CRandomGenerator & generator, std::vector & tiles, RoadId roadType); @@ -39,4 +39,4 @@ private: RmgMap & map; }; -VCMI_LIB_NAMESPACE_END \ No newline at end of file +VCMI_LIB_NAMESPACE_END From 9b40271ab1f4a8091adb7ce98e9f579908568363 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 22 Dec 2023 17:56:43 +0200 Subject: [PATCH 2/4] Update editor and tests --- mapeditor/mapcontroller.cpp | 4 +++- test/map/CMapEditManagerTest.cpp | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mapeditor/mapcontroller.cpp b/mapeditor/mapcontroller.cpp index b26bf03c1..00dcaad1c 100644 --- a/mapeditor/mapcontroller.cpp +++ b/mapeditor/mapcontroller.cpp @@ -272,6 +272,8 @@ void MapController::resetMapHandler() void MapController::commitTerrainChange(int level, const TerrainId & terrain) { + static const int terrainDecorationPercentageLevel = 10; + std::vector v(_scenes[level]->selectionTerrainView.selection().begin(), _scenes[level]->selectionTerrainView.selection().end()); if(v.empty()) @@ -281,7 +283,7 @@ void MapController::commitTerrainChange(int level, const TerrainId & terrain) _scenes[level]->selectionTerrainView.draw(); _map->getEditManager()->getTerrainSelection().setSelection(v); - _map->getEditManager()->drawTerrain(terrain, &CRandomGenerator::getDefault()); + _map->getEditManager()->drawTerrain(terrain, terrainDecorationPercentageLevel, &CRandomGenerator::getDefault()); for(auto & t : v) _scenes[level]->terrainView.setDirty(t); diff --git a/test/map/CMapEditManagerTest.cpp b/test/map/CMapEditManagerTest.cpp index aefffdbc2..b8ae125ca 100644 --- a/test/map/CMapEditManagerTest.cpp +++ b/test/map/CMapEditManagerTest.cpp @@ -34,7 +34,7 @@ TEST(MapManager, DrawTerrain_Type) // 1x1 Blow up editManager->getTerrainSelection().select(int3(5, 5, 0)); - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); static const int3 squareCheck[] = { int3(5,5,0), int3(5,4,0), int3(4,4,0), int3(4,5,0) }; for(const auto & tile : squareCheck) { @@ -43,20 +43,20 @@ TEST(MapManager, DrawTerrain_Type) // Concat to square editManager->getTerrainSelection().select(int3(6, 5, 0)); - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); EXPECT_EQ(map->getTile(int3(6, 4, 0)).terType->getId(), ETerrainId::GRASS); editManager->getTerrainSelection().select(int3(6, 5, 0)); - editManager->drawTerrain(ETerrainId::LAVA); + editManager->drawTerrain(ETerrainId::LAVA, 10); EXPECT_EQ(map->getTile(int3(4, 4, 0)).terType->getId(), ETerrainId::GRASS); EXPECT_EQ(map->getTile(int3(7, 4, 0)).terType->getId(), ETerrainId::LAVA); // Special case water,rock editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 10, 5)); - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); editManager->getTerrainSelection().selectRange(MapRect(int3(15, 17, 0), 10, 5)); - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); editManager->getTerrainSelection().select(int3(21, 16, 0)); - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); EXPECT_EQ(map->getTile(int3(20, 15, 0)).terType->getId(), ETerrainId::GRASS); // Special case non water,rock @@ -67,16 +67,16 @@ TEST(MapManager, DrawTerrain_Type) { editManager->getTerrainSelection().select(tile); } - editManager->drawTerrain(ETerrainId::GRASS); + editManager->drawTerrain(ETerrainId::GRASS, 10); EXPECT_EQ(map->getTile(int3(35, 44, 0)).terType->getId(), ETerrainId::WATER); // Rock case editManager->getTerrainSelection().selectRange(MapRect(int3(1, 1, 1), 15, 15)); - editManager->drawTerrain(ETerrainId::SUBTERRANEAN); + editManager->drawTerrain(ETerrainId::SUBTERRANEAN, 10); std::vector 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(ETerrainId::ROCK); + editManager->drawTerrain(ETerrainId::ROCK, 10); EXPECT_TRUE(!map->getTile(int3(5, 6, 1)).terType->isPassable() || !map->getTile(int3(7, 8, 1)).terType->isPassable()); //todo: add checks here and enable, also use smaller size @@ -144,7 +144,7 @@ TEST(MapManager, DrawTerrain_View) int3 pos((si32)posVector[0].Float(), (si32)posVector[1].Float(), (si32)posVector[2].Float()); const auto & originalTile = originalMap->getTile(pos); editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1)); - editManager->drawTerrain(originalTile.terType->getId(), &gen); + editManager->drawTerrain(originalTile.terType->getId(), 10, &gen); const auto & tile = map->getTile(pos); bool isInRange = false; for(const auto & range : mapping) From 8916ae7bcdddccfb33caf39e115b8afdecede1a4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 22 Dec 2023 18:35:38 +0200 Subject: [PATCH 3/4] Fix water generation, try to improve decoration level a bit --- lib/mapping/CMapOperation.cpp | 2 +- lib/rmg/RmgMap.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mapping/CMapOperation.cpp b/lib/mapping/CMapOperation.cpp index bb5ce4d7b..59e5e3261 100644 --- a/lib/mapping/CMapOperation.cpp +++ b/lib/mapping/CMapOperation.cpp @@ -292,7 +292,7 @@ void CDrawTerrainOperation::updateTerrainViews() if(pattern.decoration) { - if (gen->nextInt(100) > decorationsPercentage) + if (pattern.mapping.size() < 2 || gen->nextInt(100) > decorationsPercentage) mapping = pattern.mapping[0]; else mapping = pattern.mapping[1]; diff --git a/lib/rmg/RmgMap.cpp b/lib/rmg/RmgMap.cpp index e192d3918..639523e67 100644 --- a/lib/rmg/RmgMap.cpp +++ b/lib/rmg/RmgMap.cpp @@ -47,7 +47,7 @@ RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) : int RmgMap::getDecorationsPercentage() const { - return 10; // arbitrary value to generate more readable map + return 15; // arbitrary value to generate more readable map } void RmgMap::foreach_neighbour(const int3 & pos, const std::function & foo) const From bbbf676d388b9bab16ce9d6def21ce509ce69aae Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 22 Dec 2023 23:22:33 +0200 Subject: [PATCH 4/4] spaces -> tabs --- lib/rmg/threadpool/MapProxy.cpp | 22 +++++++++++----------- lib/rmg/threadpool/MapProxy.h | 18 +++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/rmg/threadpool/MapProxy.cpp b/lib/rmg/threadpool/MapProxy.cpp index da1ce88e9..af872e2c5 100644 --- a/lib/rmg/threadpool/MapProxy.cpp +++ b/lib/rmg/threadpool/MapProxy.cpp @@ -14,46 +14,46 @@ VCMI_LIB_NAMESPACE_BEGIN MapProxy::MapProxy(RmgMap & map): - map(map) + map(map) { } void MapProxy::insertObject(CGObjectInstance * obj) { - Lock lock(mx); - map.getEditManager()->insertObject(obj); + Lock lock(mx); + map.getEditManager()->insertObject(obj); } void MapProxy::insertObjects(std::set& objects) { - Lock lock(mx); - map.getEditManager()->insertObjects(objects); + Lock lock(mx); + map.getEditManager()->insertObjects(objects); } void MapProxy::removeObject(CGObjectInstance * obj) { - Lock lock(mx); - map.getEditManager()->removeObject(obj); + Lock lock(mx); + map.getEditManager()->removeObject(obj); } void MapProxy::drawTerrain(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain) { - Lock lock(mx); + Lock lock(mx); map.getEditManager()->getTerrainSelection().setSelection(tiles); map.getEditManager()->drawTerrain(terrain, map.getDecorationsPercentage(), &generator); } void MapProxy::drawRivers(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain) { - Lock lock(mx); + Lock lock(mx); map.getEditManager()->getTerrainSelection().setSelection(tiles); map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(terrain)->river, &generator); } void MapProxy::drawRoads(CRandomGenerator & generator, std::vector & tiles, RoadId roadType) { - Lock lock(mx); - map.getEditManager()->getTerrainSelection().setSelection(tiles); + Lock lock(mx); + map.getEditManager()->getTerrainSelection().setSelection(tiles); map.getEditManager()->drawRoad(roadType, &generator); } diff --git a/lib/rmg/threadpool/MapProxy.h b/lib/rmg/threadpool/MapProxy.h index bf74e88e7..9cb265f8f 100644 --- a/lib/rmg/threadpool/MapProxy.h +++ b/lib/rmg/threadpool/MapProxy.h @@ -22,21 +22,21 @@ class RmgMap; class MapProxy { public: - MapProxy(RmgMap & map); + MapProxy(RmgMap & map); - void insertObject(CGObjectInstance * obj); - void insertObjects(std::set& objects); - void removeObject(CGObjectInstance* obj); + void insertObject(CGObjectInstance * obj); + void insertObjects(std::set& objects); + void removeObject(CGObjectInstance* obj); void drawTerrain(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); - void drawRivers(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); - void drawRoads(CRandomGenerator & generator, std::vector & tiles, RoadId roadType); + void drawRivers(CRandomGenerator & generator, std::vector & tiles, TerrainId terrain); + void drawRoads(CRandomGenerator & generator, std::vector & tiles, RoadId roadType); private: - mutable boost::shared_mutex mx; - using Lock = boost::unique_lock; + mutable boost::shared_mutex mx; + using Lock = boost::unique_lock; - RmgMap & map; + RmgMap & map; }; VCMI_LIB_NAMESPACE_END