mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Parallel RMG works fine for maps without water.
This commit is contained in:
parent
19010dd834
commit
73d9f5bd0a
@ -94,6 +94,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatH3M.cpp
|
||||
${MAIN_LIB_DIR}/mapping/MapReaderH3M.cpp
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatJson.cpp
|
||||
${MAIN_LIB_DIR}/mapping/ObstacleProxy.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/registerTypes/RegisterTypes.cpp
|
||||
${MAIN_LIB_DIR}/registerTypes/TypesClientPacks1.cpp
|
||||
@ -135,9 +136,11 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/rmg/WaterProxy.cpp
|
||||
${MAIN_LIB_DIR}/rmg/WaterRoutes.cpp
|
||||
${MAIN_LIB_DIR}/rmg/RockPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/RockFiller.cpp
|
||||
${MAIN_LIB_DIR}/rmg/ObstaclePlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/RiverPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/TerrainPainter.cpp
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/MapProxy.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/serializer/BinaryDeserializer.cpp
|
||||
${MAIN_LIB_DIR}/serializer/BinarySerializer.cpp
|
||||
@ -387,6 +390,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatH3M.h
|
||||
${MAIN_LIB_DIR}/mapping/MapReaderH3M.h
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatJson.h
|
||||
${MAIN_LIB_DIR}/mapping/ObstacleProxy.h
|
||||
|
||||
${MAIN_LIB_DIR}/registerTypes/RegisterTypes.h
|
||||
|
||||
@ -421,13 +425,14 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/rmg/WaterProxy.h
|
||||
${MAIN_LIB_DIR}/rmg/WaterRoutes.h
|
||||
${MAIN_LIB_DIR}/rmg/RockPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/RockFiller.h
|
||||
${MAIN_LIB_DIR}/rmg/ObstaclePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/RiverPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/TerrainPainter.h
|
||||
${MAIN_LIB_DIR}/rmg/float3.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/BlockingQueue.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/ThreadPool.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/JobProvider.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/MapProxy.h
|
||||
|
||||
${MAIN_LIB_DIR}/serializer/BinaryDeserializer.h
|
||||
${MAIN_LIB_DIR}/serializer/BinarySerializer.h
|
||||
|
@ -101,7 +101,7 @@ const CMapGenOptions& CMapGenerator::getMapGenOptions() const
|
||||
void CMapGenerator::initPrisonsRemaining()
|
||||
{
|
||||
allowedPrisons = 0;
|
||||
for (auto isAllowed : map->map().allowedHeroes)
|
||||
for (auto isAllowed : map->getMap(this).allowedHeroes)
|
||||
{
|
||||
if (isAllowed)
|
||||
allowedPrisons++;
|
||||
@ -133,7 +133,7 @@ std::unique_ptr<CMap> CMapGenerator::generate()
|
||||
initQuestArtsRemaining();
|
||||
genZones();
|
||||
Load::Progress::step();
|
||||
map->map().calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
|
||||
map->getMap(this).calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
|
||||
map->addModificators();
|
||||
Load::Progress::step(3);
|
||||
fillZones();
|
||||
@ -164,7 +164,7 @@ std::string CMapGenerator::getMapDescription() const
|
||||
std::stringstream ss;
|
||||
ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
|
||||
", levels %d, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() %
|
||||
randomSeed % map->map().width % map->map().height % static_cast<int>(map->map().levels()) % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
randomSeed % map->width() % map->height() % static_cast<int>(map->levels()) % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
|
||||
monsterStrengthStr[monsterStrengthIndex]);
|
||||
|
||||
@ -263,10 +263,10 @@ void CMapGenerator::addPlayerInfo()
|
||||
teamNumbers[j].erase(itTeam);
|
||||
}
|
||||
teamsTotal.insert(player.team.getNum());
|
||||
map->map().players[pSettings.getColor().getNum()] = player;
|
||||
map->getMap(this).players[pSettings.getColor().getNum()] = player;
|
||||
}
|
||||
|
||||
map->map().howManyTeams = teamsTotal.size();
|
||||
map->getMap(this).howManyTeams = teamsTotal.size();
|
||||
}
|
||||
|
||||
void CMapGenerator::genZones()
|
||||
@ -374,7 +374,7 @@ void CMapGenerator::fillZones()
|
||||
}
|
||||
auto grailZone = *RandomGeneratorUtil::nextItem(treasureZones, rand);
|
||||
|
||||
map->map().grailPos = *RandomGeneratorUtil::nextItem(grailZone->freePaths().getTiles(), rand);
|
||||
map->getMap(this).grailPos = *RandomGeneratorUtil::nextItem(grailZone->freePaths().getTiles(), rand);
|
||||
|
||||
logGlobal->info("Zones filled successfully");
|
||||
|
||||
@ -383,13 +383,14 @@ void CMapGenerator::fillZones()
|
||||
|
||||
void CMapGenerator::addHeaderInfo()
|
||||
{
|
||||
map->map().version = EMapFormat::VCMI;
|
||||
map->map().width = mapGenOptions.getWidth();
|
||||
map->map().height = mapGenOptions.getHeight();
|
||||
map->map().twoLevel = mapGenOptions.getHasTwoLevels();
|
||||
map->map().name = VLC->generaltexth->allTexts[740];
|
||||
map->map().description = getMapDescription();
|
||||
map->map().difficulty = 1;
|
||||
auto& m = map->getMap(this);
|
||||
m.version = EMapFormat::VCMI;
|
||||
m.width = mapGenOptions.getWidth();
|
||||
m.height = mapGenOptions.getHeight();
|
||||
m.twoLevel = mapGenOptions.getHasTwoLevels();
|
||||
m.name = VLC->generaltexth->allTexts[740];
|
||||
m.description = getMapDescription();
|
||||
m.difficulty = 1;
|
||||
addPlayerInfo();
|
||||
}
|
||||
|
||||
@ -434,9 +435,9 @@ const std::vector<HeroTypeID> CMapGenerator::getAllPossibleHeroes() const
|
||||
{
|
||||
//Skip heroes that were banned, including the ones placed in prisons
|
||||
std::vector<HeroTypeID> ret;
|
||||
for (int j = 0; j < map->map().allowedHeroes.size(); j++)
|
||||
for (int j = 0; j < map->getMap(this).allowedHeroes.size(); j++)
|
||||
{
|
||||
if (map->map().allowedHeroes[j])
|
||||
if (map->getMap(this).allowedHeroes[j])
|
||||
ret.push_back(HeroTypeID(j));
|
||||
}
|
||||
return ret;
|
||||
@ -445,13 +446,13 @@ const std::vector<HeroTypeID> CMapGenerator::getAllPossibleHeroes() const
|
||||
void CMapGenerator::banQuestArt(const ArtifactID & id)
|
||||
{
|
||||
//TODO: Protect with mutex
|
||||
map->map().allowedArtifact[id] = false;
|
||||
map->getMap(this).allowedArtifact[id] = false;
|
||||
}
|
||||
|
||||
void CMapGenerator::banHero(const HeroTypeID & id)
|
||||
{
|
||||
//TODO: Protect with mutex
|
||||
map->map().allowedHeroes[id] = false;
|
||||
map->getMap(this).allowedHeroes[id] = false;
|
||||
}
|
||||
|
||||
Zone * CMapGenerator::getZoneWater() const
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "CMapGenOptions.h"
|
||||
#include "../int3.h"
|
||||
#include "CRmgTemplate.h"
|
||||
#include "threadpool/JobProvider.h"
|
||||
#include "../LoadProgress.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -38,7 +38,7 @@ CZonePlacer::CZonePlacer(RmgMap & map)
|
||||
|
||||
int3 CZonePlacer::cords(const float3 & f) const
|
||||
{
|
||||
return int3(static_cast<si32>(std::max(0.f, (f.x * map.map().width) - 1)), static_cast<si32>(std::max(0.f, (f.y * map.map().height - 1))), f.z);
|
||||
return int3(static_cast<si32>(std::max(0.f, (f.x * map.width()) - 1)), static_cast<si32>(std::max(0.f, (f.y * map.height() - 1))), f.z);
|
||||
}
|
||||
|
||||
float CZonePlacer::getDistance (float distance) const
|
||||
@ -224,8 +224,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
|
||||
|
||||
auto zoneType = zone->getType();
|
||||
auto existingZoneType = existingZone->getType();
|
||||
if ((zoneType == ETemplateZoneType::PLAYER_START || zoneType == ETemplateZoneType::CPU_START) &&
|
||||
(existingZoneType == ETemplateZoneType::PLAYER_START || existingZoneType == ETemplateZoneType::CPU_START))
|
||||
if (zone->getOwner() && existingZone->getOwner()) //Players participate in game
|
||||
{
|
||||
int firstPlayer = zone->getOwner().value();
|
||||
int secondPlayer = existingZone->getOwner().value();
|
||||
@ -785,7 +784,7 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
||||
zone->setPos(int3(total.x / size, total.y / size, total.z / size));
|
||||
};
|
||||
|
||||
int levels = map.map().levels();
|
||||
int levels = map.levels();
|
||||
|
||||
/*
|
||||
1. Create Voronoi diagram
|
||||
@ -863,7 +862,7 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
||||
|
||||
//make sure that terrain inside zone is not a rock
|
||||
//FIXME: reorder actions?
|
||||
paintZoneTerrain(*zone.second, *rand, map, ETerrainId::SUBTERRANEAN);
|
||||
paintZoneTerrain(*zone.second, *rand, map.getMapProxy(), ETerrainId::SUBTERRANEAN);
|
||||
}
|
||||
}
|
||||
logGlobal->info("Finished zone colouring");
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "WaterAdopter.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "TownPlacer.h"
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -101,7 +102,7 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
|
||||
guardPos = zone.areaPossible().nearest(borderPos);
|
||||
assert(borderPos != guardPos);
|
||||
|
||||
float dist = map.getTile(guardPos).getNearestObjectDistance();
|
||||
float dist = map.getTileInfo(guardPos).getNearestObjectDistance();
|
||||
if (dist >= 3) //Don't place guards at adjacent tiles
|
||||
{
|
||||
|
||||
@ -228,11 +229,12 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
||||
bool guarded2 = managerOther.addGuard(rmgGate2, connection.getGuardStrength(), true);
|
||||
int minDist = 3;
|
||||
|
||||
std::scoped_lock doubleLock(zone.areaMutex, otherZone->areaMutex);
|
||||
rmg::Path path2(otherZone->area());
|
||||
rmg::Path path1 = manager.placeAndConnectObject(commonArea, rmgGate1, [this, minDist, &path2, &rmgGate1, &zShift, guarded2, &managerOther, &rmgGate2 ](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto otherTi = map.getTile(tile - zShift);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
auto otherTi = map.getTileInfo(tile - zShift);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
float otherDist = otherTi.getNearestObjectDistance();
|
||||
if(dist < minDist || otherDist < minDist)
|
||||
|
@ -51,6 +51,7 @@ void createBorder(RmgMap & gen, Zone & zone)
|
||||
return gen.isOnMap(tile) && gen.getZones()[gen.getZoneID(tile)]->getType() != ETemplateZoneType::WATER;
|
||||
});
|
||||
|
||||
Zone::Lock lock(zone.areaMutex); //Protect from erasing same tiles again
|
||||
for(const auto & tile : blockBorder.getTilesVector())
|
||||
{
|
||||
if(gen.isPossible(tile))
|
||||
@ -70,11 +71,10 @@ void createBorder(RmgMap & gen, Zone & zone)
|
||||
}
|
||||
}
|
||||
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrain)
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, std::shared_ptr<MapProxy> mapProxy, TerrainId terrain)
|
||||
{
|
||||
auto v = zone.getArea().getTilesVector();
|
||||
map.getEditManager()->getTerrainSelection().setSelection(v);
|
||||
map.getEditManager()->drawTerrain(terrain, &generator);
|
||||
mapProxy->drawTerrain(generator, v, terrain);
|
||||
}
|
||||
|
||||
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId terrain)
|
||||
@ -153,15 +153,15 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
|
||||
|
||||
void createObstaclesCommon2(RmgMap & map, CRandomGenerator & generator)
|
||||
{
|
||||
if(map.map().twoLevel)
|
||||
if(map.levels())
|
||||
{
|
||||
//finally mark rock tiles as occupied, spawn no obstacles there
|
||||
for(int x = 0; x < map.map().width; x++)
|
||||
for(int x = 0; x < map.width(); x++)
|
||||
{
|
||||
for(int y = 0; y < map.map().height; y++)
|
||||
for(int y = 0; y < map.height(); y++)
|
||||
{
|
||||
int3 tile(x, y, 1);
|
||||
if(!map.map().getTile(tile).terType->isPassable())
|
||||
if(!map.getTile(tile).terType->isPassable())
|
||||
{
|
||||
map.setOccupied(tile, ETileType::USED);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
|
||||
|
||||
void createBorder(RmgMap & gen, Zone & zone);
|
||||
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrainType);
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, std::shared_ptr<MapProxy> mapProxy, TerrainId terrainType);
|
||||
|
||||
void initTerrainType(Zone & zone, CMapGenerator & gen);
|
||||
|
||||
|
@ -19,6 +19,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
Modificator::Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator) : zone(zone), map(map), generator(generator)
|
||||
{
|
||||
mapProxy = map.getMapProxy();
|
||||
}
|
||||
|
||||
void Modificator::setName(const std::string & n)
|
||||
@ -45,18 +46,16 @@ bool Modificator::isReady()
|
||||
{
|
||||
if ((*it)->isFinished()) //OK
|
||||
{
|
||||
//This preceeder won't be checked in the future
|
||||
it = preceeders.erase(it);
|
||||
}
|
||||
else if (!(*it)->isReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//If a job is finished, it should be already erased from a queue
|
||||
return !finished;
|
||||
}
|
||||
}
|
||||
@ -102,6 +101,7 @@ void Modificator::dependency(Modificator * modificator)
|
||||
{
|
||||
if(modificator && modificator != this)
|
||||
{
|
||||
//TODO: use vstd::contains
|
||||
if(std::find(preceeders.begin(), preceeders.end(), modificator) == preceeders.end())
|
||||
preceeders.push_back(modificator);
|
||||
}
|
||||
@ -119,10 +119,9 @@ void Modificator::postfunction(Modificator * modificator)
|
||||
void Modificator::dump()
|
||||
{
|
||||
std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName()));
|
||||
auto & mapInstance = map.map();
|
||||
int levels = mapInstance.levels();
|
||||
int width = mapInstance.width;
|
||||
int height = mapInstance.height;
|
||||
int levels = map.levels();
|
||||
int width = map.width();
|
||||
int height = map.height();
|
||||
for(int z = 0; z < levels; z++)
|
||||
{
|
||||
for(int j=0; j<height; j++)
|
||||
|
@ -12,14 +12,13 @@
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "../int3.h"
|
||||
#include "threadpool/JobProvider.h"
|
||||
#include "Zone.h"
|
||||
#include "threadpool/MapProxy.h"
|
||||
|
||||
class RmgMap;
|
||||
class CMapGenerator;
|
||||
class Zone;
|
||||
|
||||
|
||||
class MapProxy;
|
||||
|
||||
#define MODIFICATOR(x) x(Zone & z, RmgMap & m, CMapGenerator & g): Modificator(z, m, g) {setName(#x);}
|
||||
#define DEPENDENCY(x) dependency(zone.getModificator<x>());
|
||||
@ -57,14 +56,38 @@ public:
|
||||
|
||||
protected:
|
||||
RmgMap & map;
|
||||
std::shared_ptr<MapProxy> mapProxy;
|
||||
CMapGenerator & generator;
|
||||
Zone & zone;
|
||||
|
||||
bool finished = false;
|
||||
|
||||
mutable boost::shared_mutex externalAccessMutex; //Used to communicate between Modificators
|
||||
mutable boost::recursive_mutex externalAccessMutex; //Used to communicate between Modificators
|
||||
using RecursiveLock = boost::unique_lock<boost::recursive_mutex>;
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
|
||||
template <typename TModificator>
|
||||
std::vector<RecursiveLock> tryLockAll()
|
||||
{
|
||||
std::vector<RecursiveLock> locks;
|
||||
for (auto & zone : map.getZones())
|
||||
{
|
||||
if (auto * m = zone.second->getModificator<TModificator>())
|
||||
{
|
||||
RecursiveLock lock(m->externalAccessMutex, boost::try_to_lock_t{});
|
||||
if (lock.owns_lock())
|
||||
{
|
||||
locks.emplace_back(std::move(lock));
|
||||
}
|
||||
else //return empty
|
||||
{
|
||||
return std::vector<RecursiveLock>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return locks;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void process() = 0;
|
||||
|
||||
|
@ -27,18 +27,28 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ObjectDistributor::process()
|
||||
{
|
||||
//Firts call will add objects to ALL zones, once they were added skip it
|
||||
if (zone.getModificator<TreasurePlacer>()->getPossibleObjectsSize() == 0)
|
||||
//Do that only once
|
||||
auto lockVec = tryLockAll<ObjectDistributor>();
|
||||
if (!lockVec.empty())
|
||||
{
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<ObjectDistributor>())
|
||||
{
|
||||
if(m->isFinished())
|
||||
return;
|
||||
}
|
||||
}
|
||||
distributeLimitedObjects();
|
||||
distributeSeerHuts();
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDistributor::init()
|
||||
{
|
||||
DEPENDENCY(TownPlacer);
|
||||
DEPENDENCY(TerrainPainter);
|
||||
//All of the terrain types need to be determined
|
||||
DEPENDENCY_ALL(TerrainPainter);
|
||||
POSTFUNCTION(TreasurePlacer);
|
||||
}
|
||||
|
||||
@ -84,6 +94,8 @@ void ObjectDistributor::distributeLimitedObjects()
|
||||
//We already know there are some templates
|
||||
auto templates = handler->getTemplates(zone->getTerrainType());
|
||||
|
||||
//FIXME: Templates empty?! Maybe zone changed terrain type over time?
|
||||
|
||||
//Assume the template with fewest terrains is the most suitable
|
||||
auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
|
||||
{
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "MinePlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "QuestArtifactPlacer.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
@ -37,13 +40,16 @@ void ObjectManager::process()
|
||||
void ObjectManager::init()
|
||||
{
|
||||
DEPENDENCY(WaterAdopter);
|
||||
DEPENDENCY_ALL(ConnectionsPlacer); //Monoliths can be placed by other zone, too
|
||||
DEPENDENCY(TownPlacer); //Only secondary towns
|
||||
DEPENDENCY(MinePlacer);
|
||||
POSTFUNCTION(RoadPlacer);
|
||||
createDistancesPriorityQueue();
|
||||
}
|
||||
|
||||
void ObjectManager::createDistancesPriorityQueue()
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
tilesByDistance.clear();
|
||||
for(const auto & tile : zone.areaPossible().getTilesVector())
|
||||
{
|
||||
@ -53,25 +59,25 @@ void ObjectManager::createDistancesPriorityQueue()
|
||||
|
||||
void ObjectManager::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
requiredObjects.emplace_back(obj, strength);
|
||||
}
|
||||
|
||||
void ObjectManager::addCloseObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
closeObjects.emplace_back(obj, strength);
|
||||
}
|
||||
|
||||
void ObjectManager::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
nearbyObjects.emplace_back(obj, nearbyTarget);
|
||||
}
|
||||
|
||||
void ObjectManager::updateDistances(const rmg::Object & obj)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
tilesByDistance.clear();
|
||||
for (auto tile : zone.areaPossible().getTiles()) //don't need to mark distance for not possible tiles
|
||||
{
|
||||
@ -83,15 +89,15 @@ void ObjectManager::updateDistances(const rmg::Object & obj)
|
||||
|
||||
const rmg::Area & ObjectManager::getVisitableArea() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return objectsVisitableArea;
|
||||
}
|
||||
|
||||
std::vector<CGObjectInstance*> ObjectManager::getMines() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
std::vector<CGObjectInstance*> mines;
|
||||
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
for(auto * object : objects)
|
||||
{
|
||||
if (object->ID == Obj::MINE)
|
||||
@ -161,6 +167,7 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
}
|
||||
}
|
||||
|
||||
//FIXME: Race condition for tiles? For Area?
|
||||
if(result.valid())
|
||||
obj.setPosition(result);
|
||||
return result;
|
||||
@ -170,14 +177,14 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
{
|
||||
return findPlaceForObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
if(dist < min_dist)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : obj.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < min_dist)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
@ -189,14 +196,14 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
||||
{
|
||||
return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
if(dist < min_dist)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : obj.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < min_dist)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
@ -251,13 +258,17 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
||||
bool ObjectManager::createRequiredObjects()
|
||||
{
|
||||
logGlobal->trace("Creating required objects");
|
||||
|
||||
|
||||
//RecursiveLock lock(externalAccessMutex); //Why could requiredObjects be modified during the loop?
|
||||
for(const auto & object : requiredObjects)
|
||||
{
|
||||
auto * obj = object.first;
|
||||
//FIXME: Invalid dObject inside object?
|
||||
rmg::Object rmgObject(*obj);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject, 3, guarded, false, OptimizeType::DISTANCE);
|
||||
|
||||
if(!path.valid())
|
||||
@ -291,7 +302,11 @@ bool ObjectManager::createRequiredObjects()
|
||||
for(const auto & object : closeObjects)
|
||||
{
|
||||
auto * obj = object.first;
|
||||
|
||||
//TODO: Wrap into same area proxy?
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
auto possibleArea = zone.areaPossible();
|
||||
|
||||
rmg::Object rmgObject(*obj);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||
@ -352,6 +367,8 @@ bool ObjectManager::createRequiredObjects()
|
||||
void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance)
|
||||
{
|
||||
object.finalize(map);
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
zone.areaPossible().subtract(object.getArea());
|
||||
bool keepVisitable = zone.freePaths().contains(object.getVisitablePosition());
|
||||
zone.freePaths().subtract(object.getArea()); //just to avoid areas overlapping
|
||||
|
@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "TreasurePlacer.h"
|
||||
@ -24,186 +23,16 @@
|
||||
#include "Functions.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/ObstacleProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ObstacleProxy::collectPossibleObstacles(TerrainId terrain)
|
||||
{
|
||||
//get all possible obstacles for this terrain
|
||||
for(auto primaryID : VLC->objtypeh->knownObjects())
|
||||
{
|
||||
for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID))
|
||||
{
|
||||
auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);
|
||||
if(handler->isStaticObject())
|
||||
{
|
||||
for(const auto & temp : handler->getTemplates())
|
||||
{
|
||||
if(temp->canBePlacedAt(terrain) && temp->getBlockMapOffset().valid())
|
||||
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const auto & o : obstaclesBySize)
|
||||
{
|
||||
possibleObstacles.emplace_back(o);
|
||||
}
|
||||
boost::sort(possibleObstacles, [](const ObstaclePair &p1, const ObstaclePair &p2) -> bool
|
||||
{
|
||||
return p1.first > p2.first; //bigger obstacles first
|
||||
});
|
||||
}
|
||||
|
||||
int ObstacleProxy::getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects)
|
||||
{
|
||||
int maxWeight = std::numeric_limits<int>::min();
|
||||
for(auto & possibleObstacle : possibleObstacles)
|
||||
{
|
||||
if(!possibleObstacle.first)
|
||||
continue;
|
||||
|
||||
auto shuffledObstacles = possibleObstacle.second;
|
||||
RandomGeneratorUtil::randomShuffle(shuffledObstacles, rand);
|
||||
|
||||
for(const auto & temp : shuffledObstacles)
|
||||
{
|
||||
auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid);
|
||||
auto * obj = handler->create(temp);
|
||||
allObjects.emplace_back(*obj);
|
||||
rmg::Object * rmgObject = &allObjects.back();
|
||||
for(const auto & offset : obj->getBlockedOffsets())
|
||||
{
|
||||
rmgObject->setPosition(tile - offset);
|
||||
if(!map->isInTheMap(rmgObject->getPosition()))
|
||||
continue;
|
||||
|
||||
if(!rmgObject->getArea().getSubarea([map](const int3 & t)
|
||||
{
|
||||
return !map->isInTheMap(t);
|
||||
}).empty())
|
||||
continue;
|
||||
|
||||
if(isProhibited(rmgObject->getArea()))
|
||||
continue;
|
||||
|
||||
int coverageBlocked = 0;
|
||||
int coveragePossible = 0;
|
||||
//do not use area intersection in optimization purposes
|
||||
for(const auto & t : rmgObject->getArea().getTilesVector())
|
||||
{
|
||||
auto coverage = verifyCoverage(t);
|
||||
if(coverage.first)
|
||||
++coverageBlocked;
|
||||
if(coverage.second)
|
||||
++coveragePossible;
|
||||
}
|
||||
|
||||
int coverageOverlap = possibleObstacle.first - coverageBlocked - coveragePossible;
|
||||
int weight = possibleObstacle.first + coverageBlocked - coverageOverlap * possibleObstacle.first;
|
||||
assert(coverageOverlap >= 0);
|
||||
|
||||
if(weight > maxWeight)
|
||||
{
|
||||
weightedObjects.clear();
|
||||
maxWeight = weight;
|
||||
weightedObjects.emplace_back(rmgObject, rmgObject->getPosition());
|
||||
if(weight > 0)
|
||||
break;
|
||||
}
|
||||
else if(weight == maxWeight)
|
||||
weightedObjects.emplace_back(rmgObject, rmgObject->getPosition());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(maxWeight > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return maxWeight;
|
||||
}
|
||||
|
||||
void ObstacleProxy::placeObstacles(CMap * map, CRandomGenerator & rand)
|
||||
{
|
||||
//reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left
|
||||
auto blockedTiles = blockedArea.getTilesVector();
|
||||
int tilePos = 0;
|
||||
std::set<CGObjectInstance*> objs;
|
||||
|
||||
while(!blockedArea.empty() && tilePos < blockedArea.getTilesVector().size())
|
||||
{
|
||||
auto tile = blockedArea.getTilesVector()[tilePos];
|
||||
|
||||
std::list<rmg::Object> allObjects;
|
||||
std::vector<std::pair<rmg::Object*, int3>> weightedObjects;
|
||||
int maxWeight = getWeightedObjects(tile, map, rand, allObjects, weightedObjects);
|
||||
|
||||
if(weightedObjects.empty())
|
||||
{
|
||||
tilePos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto objIter = RandomGeneratorUtil::nextItem(weightedObjects, rand);
|
||||
objIter->first->setPosition(objIter->second);
|
||||
placeObject(*objIter->first, objs);
|
||||
|
||||
blockedArea.subtract(objIter->first->getArea());
|
||||
tilePos = 0;
|
||||
|
||||
postProcess(*objIter->first);
|
||||
|
||||
if(maxWeight < 0)
|
||||
logGlobal->warn("Placed obstacle with negative weight at %s", objIter->second.toString());
|
||||
|
||||
for(auto & o : allObjects)
|
||||
{
|
||||
if(&o != objIter->first)
|
||||
o.clear();
|
||||
}
|
||||
}
|
||||
|
||||
finalInsertion(map->getEditManager(), objs);
|
||||
}
|
||||
|
||||
void ObstacleProxy::finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances)
|
||||
{
|
||||
manager->insertObjects(instances); //insert as one operation - for undo purposes
|
||||
}
|
||||
|
||||
std::pair<bool, bool> ObstacleProxy::verifyCoverage(const int3 & t) const
|
||||
{
|
||||
return {blockedArea.contains(t), false};
|
||||
}
|
||||
|
||||
void ObstacleProxy::placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances)
|
||||
{
|
||||
for (auto * instance : object.instances())
|
||||
{
|
||||
instances.insert(&instance->object());
|
||||
}
|
||||
}
|
||||
|
||||
void ObstacleProxy::postProcess(const rmg::Object & object)
|
||||
{
|
||||
}
|
||||
|
||||
bool ObstacleProxy::isProhibited(const rmg::Area & objArea) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObstaclePlacer::process()
|
||||
{
|
||||
manager = zone.getModificator<ObjectManager>();
|
||||
if(!manager)
|
||||
return;
|
||||
|
||||
riverManager = zone.getModificator<RiverPlacer>();
|
||||
|
||||
|
||||
collectPossibleObstacles(zone.getTerrainType());
|
||||
|
||||
blockedArea = zone.area().getSubarea([this](const int3 & t)
|
||||
@ -212,10 +41,12 @@ void ObstaclePlacer::process()
|
||||
});
|
||||
blockedArea.subtract(zone.areaUsed());
|
||||
zone.areaPossible().subtract(blockedArea);
|
||||
|
||||
|
||||
//TODO: Set prohibited area in ObstacleProxy :?
|
||||
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
||||
|
||||
placeObstacles(&map.map(), generator.rand);
|
||||
|
||||
auto objs = createObstacles(generator.rand);
|
||||
mapProxy->insertObjects(objs);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::init()
|
||||
@ -228,9 +59,9 @@ void ObstaclePlacer::init()
|
||||
DEPENDENCY_ALL(RockPlacer);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> ObstaclePlacer::verifyCoverage(const int3 & t) const
|
||||
bool ObstaclePlacer::isInTheMap(const int3& tile)
|
||||
{
|
||||
return {map.shouldBeBlocked(t), zone.areaPossible().contains(t)};
|
||||
return map.isOnMap(tile);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::placeObject(rmg::Object & object, std::set<CGObjectInstance*> &)
|
||||
@ -238,9 +69,15 @@ void ObstaclePlacer::placeObject(rmg::Object & object, std::set<CGObjectInstance
|
||||
manager->placeObject(object, false, false);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> ObstaclePlacer::verifyCoverage(const int3 & t) const
|
||||
{
|
||||
return {map.shouldBeBlocked(t), zone.areaPossible().contains(t)};
|
||||
}
|
||||
|
||||
void ObstaclePlacer::postProcess(const rmg::Object & object)
|
||||
{
|
||||
//river processing
|
||||
riverManager = zone.getModificator<RiverPlacer>();
|
||||
if(riverManager)
|
||||
{
|
||||
const auto objTypeName = object.instances().front()->object().typeName;
|
||||
@ -262,8 +99,4 @@ bool ObstaclePlacer::isProhibited(const rmg::Area & objArea) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObstaclePlacer::finalInsertion(CMapEditManager *, std::set<CGObjectInstance*> &)
|
||||
{
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -9,7 +9,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
|
||||
#include "Modificator.h"
|
||||
#include "../mapping/ObstacleProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -17,38 +19,6 @@ class CMap;
|
||||
class CMapEditManager;
|
||||
class RiverPlacer;
|
||||
class ObjectManager;
|
||||
|
||||
class DLL_LINKAGE ObstacleProxy
|
||||
{
|
||||
public:
|
||||
ObstacleProxy() = default;
|
||||
virtual ~ObstacleProxy() = default;
|
||||
|
||||
rmg::Area blockedArea;
|
||||
|
||||
void collectPossibleObstacles(TerrainId terrain);
|
||||
|
||||
void placeObstacles(CMap * map, CRandomGenerator & rand);
|
||||
|
||||
virtual std::pair<bool, bool> verifyCoverage(const int3 & t) const;
|
||||
|
||||
virtual void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
virtual void postProcess(const rmg::Object & object);
|
||||
|
||||
virtual bool isProhibited(const rmg::Area & objArea) const;
|
||||
|
||||
virtual void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
protected:
|
||||
int getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects);
|
||||
|
||||
using ObstacleVector = std::vector<std::shared_ptr<const ObjectTemplate>>;
|
||||
std::map<int, ObstacleVector> obstaclesBySize;
|
||||
using ObstaclePair = std::pair<int, ObstacleVector>;
|
||||
std::vector<ObstaclePair> possibleObstacles;
|
||||
};
|
||||
|
||||
class ObstaclePlacer: public Modificator, public ObstacleProxy
|
||||
{
|
||||
public:
|
||||
@ -56,6 +26,8 @@ public:
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
|
||||
bool isInTheMap(const int3& tile) override;
|
||||
|
||||
std::pair<bool, bool> verifyCoverage(const int3 & t) const override;
|
||||
|
||||
@ -65,8 +37,6 @@ public:
|
||||
|
||||
bool isProhibited(const rmg::Area & objArea) const override;
|
||||
|
||||
void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances) override;
|
||||
|
||||
private:
|
||||
rmg::Area prohibitedArea;
|
||||
RiverPlacer * riverManager;
|
||||
|
@ -33,26 +33,26 @@ void QuestArtifactPlacer::init()
|
||||
|
||||
void QuestArtifactPlacer::addQuestArtZone(std::shared_ptr<Zone> otherZone)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
questArtZones.push_back(otherZone);
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::addQuestArtifact(const ArtifactID& id)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
logGlobal->info("Need to place quest artifact artifact %s", VLC->artifacts()->getById(id)->getNameTranslated());
|
||||
questArtifactsToPlace.emplace_back(id);
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::rememberPotentialArtifactToReplace(CGObjectInstance* obj)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
artifactsToReplace.push_back(obj);
|
||||
}
|
||||
|
||||
std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplace() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return artifactsToReplace;
|
||||
}
|
||||
|
||||
@ -113,19 +113,19 @@ void QuestArtifactPlacer::placeQuestArtifacts(CRandomGenerator * rand)
|
||||
|
||||
void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
boost::remove(artifactsToReplace, obj);
|
||||
}
|
||||
|
||||
size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return questArtifacts.size();
|
||||
}
|
||||
|
||||
ArtifactID QuestArtifactPlacer::drawRandomArtifact()
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
if (!questArtifacts.empty())
|
||||
{
|
||||
ArtifactID ret = questArtifacts.back();
|
||||
@ -141,6 +141,6 @@ ArtifactID QuestArtifactPlacer::drawRandomArtifact()
|
||||
|
||||
void QuestArtifactPlacer::addRandomArtifact(ArtifactID artid)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
questArtifacts.push_back(artid);
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ void RiverPlacer::init()
|
||||
|
||||
void RiverPlacer::drawRivers()
|
||||
{
|
||||
map.getEditManager()->getTerrainSelection().setSelection(rivers.getTilesVector());
|
||||
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(zone.getTerrainType())->river, &generator.rand);
|
||||
auto tiles = rivers.getTilesVector();
|
||||
mapProxy->drawRivers(generator.rand, tiles, zone.getTerrainType());
|
||||
}
|
||||
|
||||
char RiverPlacer::dump(const int3 & t)
|
||||
@ -147,9 +147,9 @@ void RiverPlacer::prepareHeightmap()
|
||||
}
|
||||
|
||||
//make grid
|
||||
for(int j = 0; j < map.map().height; j += 2)
|
||||
for(int j = 0; j < map.height(); j += 2)
|
||||
{
|
||||
for(int i = 0; i < map.map().width; i += 2)
|
||||
for(int i = 0; i < map.width(); i += 2)
|
||||
{
|
||||
int3 t{i, j, zone.getPos().z};
|
||||
if(zone.area().contains(t))
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "WaterProxy.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "RockFiller.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "TerrainPainter.h"
|
||||
@ -40,6 +41,7 @@ RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) :
|
||||
mapGenOptions(mapGenOptions), zonesTotal(0)
|
||||
{
|
||||
mapInstance = std::make_unique<CMap>();
|
||||
mapProxy = std::make_shared<MapProxy>(*this);
|
||||
getEditManager()->getUndoManager().setUndoRedoLimit(0);
|
||||
}
|
||||
|
||||
@ -121,7 +123,7 @@ void RmgMap::addModificators()
|
||||
auto zone = z.second;
|
||||
|
||||
zone->addModificator<ObjectManager>();
|
||||
zone->addModificator<ObjectDistributor>();
|
||||
zone->addModificator<ObjectDistributor>(); //FIXME: Only one is needed for map
|
||||
zone->addModificator<TreasurePlacer>();
|
||||
zone->addModificator<ObstaclePlacer>();
|
||||
zone->addModificator<TerrainPainter>();
|
||||
@ -149,12 +151,38 @@ void RmgMap::addModificators()
|
||||
if(zone->isUnderground())
|
||||
{
|
||||
zone->addModificator<RockPlacer>();
|
||||
zone->addModificator<RockFiller>(); //FIXME: Only one is needed for map
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CMap & RmgMap::map() const
|
||||
int RmgMap::levels() const
|
||||
{
|
||||
return mapInstance->levels();
|
||||
}
|
||||
|
||||
int RmgMap::width() const
|
||||
{
|
||||
return mapInstance->width;
|
||||
}
|
||||
|
||||
int RmgMap::height() const
|
||||
{
|
||||
return mapInstance->height;
|
||||
}
|
||||
|
||||
PlayerInfo & RmgMap::getPlayer(int playerId)
|
||||
{
|
||||
return mapInstance->players.at(playerId);
|
||||
}
|
||||
|
||||
std::shared_ptr<MapProxy> RmgMap::getMapProxy() const
|
||||
{
|
||||
return mapProxy;
|
||||
}
|
||||
|
||||
CMap& RmgMap::getMap(const CMapGenerator*) const
|
||||
{
|
||||
return *mapInstance;
|
||||
}
|
||||
@ -241,13 +269,18 @@ void RmgMap::setRoad(const int3& tile, RoadId roadType)
|
||||
tiles[tile.x][tile.y][tile.z].setRoadType(roadType);
|
||||
}
|
||||
|
||||
TileInfo RmgMap::getTile(const int3& tile) const
|
||||
TileInfo RmgMap::getTileInfo(const int3& tile) const
|
||||
{
|
||||
assertOnMap(tile);
|
||||
|
||||
return tiles[tile.x][tile.y][tile.z];
|
||||
}
|
||||
|
||||
TerrainTile & RmgMap::getTile(const int3& tile) const
|
||||
{
|
||||
return mapInstance->getTile(tile);
|
||||
}
|
||||
|
||||
TRmgTemplateZoneId RmgMap::getZoneID(const int3& tile) const
|
||||
{
|
||||
assertOnMap(tile);
|
||||
@ -278,6 +311,7 @@ float RmgMap::getNearestObjectDistance(const int3 &tile) const
|
||||
|
||||
void RmgMap::registerZone(FactionID faction)
|
||||
{
|
||||
//FIXME: Protect with lock guard?
|
||||
zonesPerFaction[faction]++;
|
||||
zonesTotal++;
|
||||
}
|
||||
@ -323,7 +357,7 @@ void RmgMap::dump(bool zoneId) const
|
||||
else
|
||||
{
|
||||
char t = '?';
|
||||
switch (getTile(int3(i, j, k)).getTileType())
|
||||
switch (getTileInfo(int3(i, j, k)).getTileType())
|
||||
{
|
||||
case ETileType::FREE:
|
||||
t = ' '; break;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#pragma once
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "threadpool/MapProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -20,12 +21,15 @@ class TileInfo;
|
||||
class CMapGenOptions;
|
||||
class Zone;
|
||||
class CMapGenerator;
|
||||
class MapProxy;
|
||||
class playerInfo;
|
||||
|
||||
class RmgMap
|
||||
{
|
||||
public:
|
||||
mutable std::unique_ptr<CMap> mapInstance;
|
||||
CMap & map() const;
|
||||
std::shared_ptr<MapProxy> getMapProxy() const;
|
||||
CMap & getMap(const CMapGenerator *) const; //limited access
|
||||
|
||||
RmgMap(const CMapGenOptions& mapGenOptions);
|
||||
~RmgMap() = default;
|
||||
@ -44,11 +48,17 @@ public:
|
||||
bool isUsed(const int3 &tile) const;
|
||||
bool isRoad(const int3 &tile) const;
|
||||
bool isOnMap(const int3 & tile) const;
|
||||
|
||||
int levels() const;
|
||||
int width() const;
|
||||
int height() const;
|
||||
PlayerInfo & getPlayer(int playerId);
|
||||
|
||||
void setOccupied(const int3 &tile, ETileType::ETileType state);
|
||||
void setRoad(const int3 &tile, RoadId roadType);
|
||||
|
||||
TileInfo getTile(const int3 & tile) const;
|
||||
TileInfo getTileInfo(const int3 & tile) const;
|
||||
TerrainTile & getTile(const int3 & tile) const;
|
||||
|
||||
float getNearestObjectDistance(const int3 &tile) const;
|
||||
void setNearestObjectDistance(int3 &tile, float value);
|
||||
@ -76,6 +86,9 @@ private:
|
||||
void assertOnMap(const int3 &tile) const; //throws
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<MapProxy> mapProxy;
|
||||
|
||||
Zones zones;
|
||||
std::map<FactionID, ui32> zonesPerFaction;
|
||||
ui32 zonesTotal; //zones that have their main town only
|
||||
|
@ -182,7 +182,7 @@ std::list<Object::Instance*> Object::instances()
|
||||
{
|
||||
std::list<Object::Instance*> result;
|
||||
for(auto & i : dInstances)
|
||||
result.push_back(&i);
|
||||
result.push_back(&i); //FIXME: Sterta zosta³a uskzodzona :? Mo¿e w innym miejscu?
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
//If no specific template was defined for this object, select any matching
|
||||
if (!dObject.appearance)
|
||||
{
|
||||
const auto * terrainType = map.map().getTile(getPosition(true)).terType;
|
||||
const auto * terrainType = map.getTile(getPosition(true)).terType;
|
||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->getId());
|
||||
if (templates.empty())
|
||||
{
|
||||
@ -336,7 +336,7 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
map.setOccupied(tile, ETileType::ETileType::USED);
|
||||
}
|
||||
|
||||
map.getEditManager()->insertObject(&dObject);
|
||||
map.getMapProxy()->insertObject(&dObject);
|
||||
}
|
||||
|
||||
void Object::finalize(RmgMap & map)
|
||||
|
@ -11,10 +11,11 @@
|
||||
#include "StdInc.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "threadpool/MapProxy.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "RmgPath.h"
|
||||
@ -76,19 +77,25 @@ void RoadPlacer::drawRoads(bool secondary)
|
||||
|| (!secondary && generator.getConfig().defaultRoadType.empty()))
|
||||
return;
|
||||
|
||||
Lock lock(externalAccessMutex);
|
||||
zone.areaPossible().subtract(roads);
|
||||
zone.freePaths().unite(roads);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(roads.getTilesVector());
|
||||
//RecursiveLock lock(externalAccessMutex);
|
||||
{
|
||||
//FIXME: double lock - unsafe
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
|
||||
zone.areaPossible().subtract(roads);
|
||||
zone.freePaths().unite(roads);
|
||||
}
|
||||
|
||||
auto tiles = roads.getTilesVector();
|
||||
|
||||
std::string roadName = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
|
||||
RoadId roadType(*VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "road", roadName));
|
||||
map.getEditManager()->drawRoad(roadType, &generator.rand);
|
||||
mapProxy->drawRoads(generator.rand, tiles, roadType);
|
||||
}
|
||||
|
||||
void RoadPlacer::addRoadNode(const int3& node)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
roadNodes.insert(node);
|
||||
}
|
||||
|
||||
@ -113,7 +120,7 @@ void RoadPlacer::connectRoads()
|
||||
return;
|
||||
|
||||
//take any tile from road nodes as destination zone for all other road nodes
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
if(roads.empty())
|
||||
roads.add(*roadNodes.begin());
|
||||
|
||||
|
91
lib/rmg/RockFiller.cpp
Normal file
91
lib/rmg/RockFiller.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* RockFiller.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "RockFiller.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "RmgMap.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "Functions.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "TileInfo.h"
|
||||
#include "threadpool/MapProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class TileInfo;
|
||||
|
||||
void RockFiller::process()
|
||||
{
|
||||
//Do that only once
|
||||
auto lockVec = tryLockAll<RockFiller>();
|
||||
if (!lockVec.empty())
|
||||
{
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockFiller>())
|
||||
{
|
||||
if(m->isFinished())
|
||||
return;
|
||||
}
|
||||
}
|
||||
logGlobal->info("Processing RockFiller for the whole map");
|
||||
processMap();
|
||||
finished = true; //Block other placers immediately
|
||||
}
|
||||
}
|
||||
|
||||
void RockFiller::processMap()
|
||||
{
|
||||
//Merge all areas
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
auto tiles = m->rockArea.getTilesVector();
|
||||
mapProxy->drawTerrain(generator.rand, tiles, m->rockTerrain);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
//Now make sure all accessible tiles have no additional rock on them
|
||||
auto tiles = m->accessibleArea.getTilesVector();
|
||||
mapProxy->drawTerrain(generator.rand, tiles, z.second->getTerrainType());
|
||||
|
||||
m->postProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RockFiller::init()
|
||||
{
|
||||
DEPENDENCY_ALL(RockPlacer);
|
||||
POSTFUNCTION_ALL(RoadPlacer);
|
||||
}
|
||||
|
||||
char RockFiller::dump(const int3 & t)
|
||||
{
|
||||
if(!map.getTile(t).terType->isPassable())
|
||||
{
|
||||
return zone.area().contains(t) ? 'R' : 'E';
|
||||
}
|
||||
return Modificator::dump(t);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
28
lib/rmg/RockFiller.h
Normal file
28
lib/rmg/RockFiller.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* RockFiller.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RockFiller: public Modificator
|
||||
{
|
||||
public:
|
||||
MODIFICATOR(RockFiller);
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
char dump(const int3 &) override;
|
||||
|
||||
void processMap();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -20,71 +20,45 @@
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "TileInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class TileInfo;
|
||||
|
||||
void RockPlacer::process()
|
||||
{
|
||||
blockRock();
|
||||
}
|
||||
void RockPlacer::blockRock()
|
||||
{
|
||||
rockTerrain = VLC->terrainTypeHandler->getById(zone.getTerrainType())->rockTerrain;
|
||||
assert(!VLC->terrainTypeHandler->getById(rockTerrain)->isPassable());
|
||||
|
||||
|
||||
accessibleArea = zone.freePaths() + zone.areaUsed();
|
||||
if(auto * m = zone.getModificator<ObjectManager>())
|
||||
accessibleArea.unite(m->getVisitableArea());
|
||||
|
||||
|
||||
//negative approach - create rock tiles first, then make sure all accessible tiles have no rock
|
||||
rockArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return map.shouldBeBlocked(t);
|
||||
});
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
if(m != this && !m->isFinished())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processMap();
|
||||
}
|
||||
|
||||
void RockPlacer::processMap()
|
||||
{
|
||||
//merge all areas
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
map.getEditManager()->getTerrainSelection().setSelection(m->rockArea.getTilesVector());
|
||||
map.getEditManager()->drawTerrain(m->rockTerrain, &generator.rand);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
//now make sure all accessible tiles have no additional rock on them
|
||||
map.getEditManager()->getTerrainSelection().setSelection(m->accessibleArea.getTilesVector());
|
||||
map.getEditManager()->drawTerrain(z.second->getTerrainType(), &generator.rand);
|
||||
m->postProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RockPlacer::postProcess()
|
||||
{
|
||||
//finally mark rock tiles as occupied, spawn no obstacles there
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
//Finally mark rock tiles as occupied, spawn no obstacles there
|
||||
rockArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return !map.map().getTile(t).terType->isPassable();
|
||||
return !map.getTile(t).terType->isPassable();
|
||||
});
|
||||
|
||||
zone.areaUsed().unite(rockArea);
|
||||
zone.areaPossible().subtract(rockArea);
|
||||
|
||||
//TODO: Might need mutex here as well
|
||||
if(auto * m = zone.getModificator<RiverPlacer>())
|
||||
m->riverProhibit().unite(rockArea);
|
||||
if(auto * m = zone.getModificator<RoadPlacer>())
|
||||
@ -93,13 +67,12 @@ void RockPlacer::postProcess()
|
||||
|
||||
void RockPlacer::init()
|
||||
{
|
||||
POSTFUNCTION_ALL(RoadPlacer);
|
||||
DEPENDENCY(TreasurePlacer);
|
||||
DEPENDENCY_ALL(TreasurePlacer);
|
||||
}
|
||||
|
||||
char RockPlacer::dump(const int3 & t)
|
||||
{
|
||||
if(!map.map().getTile(t).terType->isPassable())
|
||||
if(!map.getTile(t).terType->isPassable())
|
||||
{
|
||||
return zone.area().contains(t) ? 'R' : 'E';
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RockPlacer: public Modificator
|
||||
{
|
||||
friend class RockFiller;
|
||||
public:
|
||||
MODIFICATOR(RockPlacer);
|
||||
|
||||
@ -22,7 +23,7 @@ public:
|
||||
void init() override;
|
||||
char dump(const int3 &) override;
|
||||
|
||||
void processMap();
|
||||
void blockRock();
|
||||
void postProcess();
|
||||
|
||||
protected:
|
||||
|
@ -23,8 +23,10 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void TerrainPainter::process()
|
||||
{
|
||||
//TODO: Make member methods
|
||||
|
||||
initTerrainType(zone, generator);
|
||||
paintZoneTerrain(zone, generator.rand, map, zone.getTerrainType());
|
||||
paintZoneTerrain(zone, generator.rand, mapProxy, zone.getTerrainType());
|
||||
}
|
||||
|
||||
void TerrainPainter::init()
|
||||
|
@ -52,7 +52,7 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
//set zone types to player faction, generate main town
|
||||
logGlobal->info("Preparing playing zone");
|
||||
int player_id = *zone.getOwner() - 1;
|
||||
auto & playerInfo = map.map().players[player_id];
|
||||
auto& playerInfo = map.getPlayer(player_id);
|
||||
PlayerColor player(player_id);
|
||||
if(playerInfo.canAnyonePlay())
|
||||
{
|
||||
@ -140,11 +140,16 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town)
|
||||
//towns are big objects and should be centered around visitable position
|
||||
rmg::Object rmgObject(town);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
auto position = manager.findPlaceForObject(zone.areaPossible(), rmgObject, [this](const int3 & t)
|
||||
|
||||
int3 position(-1, -1, -1);
|
||||
{
|
||||
float distance = zone.getPos().dist2dSQ(t);
|
||||
return 100000.f - distance; //some big number
|
||||
}, ObjectManager::OptimizeType::WEIGHT);
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
position = manager.findPlaceForObject(zone.areaPossible(), rmgObject, [this](const int3& t)
|
||||
{
|
||||
float distance = zone.getPos().dist2dSQ(t);
|
||||
return 100000.f - distance; //some big number
|
||||
}, ObjectManager::OptimizeType::WEIGHT);
|
||||
}
|
||||
rmgObject.setPosition(position + int3(2, 2, 0)); //place visitable tile in the exact center of a zone
|
||||
manager.placeObject(rmgObject, false, true);
|
||||
cleanupBoundaries(rmgObject);
|
||||
@ -154,6 +159,7 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town)
|
||||
|
||||
void TownPlacer::cleanupBoundaries(const rmg::Object & rmgObject)
|
||||
{
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
for(const auto & t : rmgObject.getArea().getBorderOutside())
|
||||
{
|
||||
if(map.isOnMap(t))
|
||||
|
@ -45,7 +45,7 @@ void TreasurePlacer::init()
|
||||
|
||||
void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
possibleObjects.push_back(oi);
|
||||
}
|
||||
|
||||
@ -526,19 +526,19 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
size_t TreasurePlacer::getPossibleObjectsSize() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return possibleObjects.size();
|
||||
}
|
||||
|
||||
void TreasurePlacer::setMaxPrisons(size_t count)
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
maxPrisons = count;
|
||||
}
|
||||
|
||||
size_t TreasurePlacer::getMaxPrisons() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return maxPrisons;
|
||||
}
|
||||
|
||||
@ -772,6 +772,8 @@ void TreasurePlacer::createTreasures(ObjectManager & manager)
|
||||
if(guarded)
|
||||
guarded = manager.addGuard(rmgObject, value);
|
||||
|
||||
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
|
||||
//TODO: Don't place
|
||||
auto possibleArea = zone.areaPossible();
|
||||
|
||||
auto path = rmg::Path::invalid();
|
||||
@ -779,13 +781,13 @@ void TreasurePlacer::createTreasures(ObjectManager & manager)
|
||||
{
|
||||
path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
if(ti.getNearestObjectDistance() < minDistance)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : rmgObject.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < minDistance)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < minDistance)
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,7 @@ void WaterAdopter::createWater(EWaterContent::EWaterContent waterContent)
|
||||
}
|
||||
|
||||
map.getZones()[waterZoneId]->area().unite(waterArea);
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
zone.area().subtract(waterArea);
|
||||
zone.areaPossible().subtract(waterArea);
|
||||
distanceMap = zone.area().computeDistanceMap(reverseDistanceMap);
|
||||
|
@ -38,7 +38,7 @@ void WaterProxy::process()
|
||||
map.setOccupied(t, ETileType::POSSIBLE);
|
||||
}
|
||||
|
||||
paintZoneTerrain(zone, generator.rand, map, zone.getTerrainType());
|
||||
paintZoneTerrain(zone, generator.rand, mapProxy, zone.getTerrainType());
|
||||
|
||||
//check terrain type
|
||||
for([[maybe_unused]] const auto & t : zone.area().getTilesVector())
|
||||
@ -52,9 +52,10 @@ void WaterProxy::process()
|
||||
if(z.second->getId() == zone.getId())
|
||||
continue;
|
||||
|
||||
Zone::Lock lock(z.second->areaMutex);
|
||||
for(const auto & t : z.second->area().getTilesVector())
|
||||
{
|
||||
if(map.map().getTile(t).terType->getId() == zone.getTerrainType())
|
||||
if(map.getTile(t).terType->getId() == zone.getTerrainType())
|
||||
{
|
||||
z.second->areaPossible().erase(t);
|
||||
z.second->area().erase(t);
|
||||
@ -90,13 +91,13 @@ void WaterProxy::init()
|
||||
|
||||
const std::vector<WaterProxy::Lake> & WaterProxy::getLakes() const
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return lakes;
|
||||
}
|
||||
|
||||
void WaterProxy::collectLakes()
|
||||
{
|
||||
Lock lock(externalAccessMutex);
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
int lakeId = 0;
|
||||
for(const auto & lake : connectedAreas(zone.getArea(), true))
|
||||
{
|
||||
@ -140,6 +141,8 @@ RouteInfo WaterProxy::waterRoute(Zone & dst)
|
||||
if(map.isPossible(ct))
|
||||
map.setOccupied(ct, ETileType::BLOCKED);
|
||||
}
|
||||
|
||||
Zone::Lock lock(dst.areaMutex);
|
||||
dst.areaPossible().subtract(lake.neighbourZones[dst.getId()]);
|
||||
continue;
|
||||
}
|
||||
@ -223,7 +226,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
|
||||
auto boardingPositions = coast.getSubarea([&waterAvailable, this](const int3 & tile) //tiles where boarding is possible
|
||||
{
|
||||
//We don't want place boat right to any land object, especiallly the zone guard
|
||||
if (map.getTile(tile).getNearestObjectDistance() <= 3)
|
||||
if (map.getTileInfo(tile).getNearestObjectDistance() <= 3)
|
||||
return false;
|
||||
|
||||
rmg::Area a({tile});
|
||||
|
@ -44,7 +44,9 @@ void WaterRoutes::process()
|
||||
if(z.first != zone.getId())
|
||||
result.push_back(wproxy->waterRoute(*z.second));
|
||||
}
|
||||
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
|
||||
//prohibit to place objects on sealed off lakes
|
||||
for(const auto & lake : wproxy->getLakes())
|
||||
{
|
||||
|
@ -86,6 +86,7 @@ rmg::Area & Zone::area()
|
||||
|
||||
rmg::Area & Zone::areaPossible()
|
||||
{
|
||||
//FIXME: make const, only modify via mutex-protected interface
|
||||
return dAreaPossible;
|
||||
}
|
||||
|
||||
@ -96,6 +97,7 @@ rmg::Area & Zone::areaUsed()
|
||||
|
||||
void Zone::clearTiles()
|
||||
{
|
||||
//Lock lock(mx);
|
||||
dArea.clear();
|
||||
dAreaPossible.clear();
|
||||
dAreaFree.clear();
|
||||
@ -104,6 +106,7 @@ void Zone::clearTiles()
|
||||
void Zone::initFreeTiles()
|
||||
{
|
||||
rmg::Tileset possibleTiles;
|
||||
//Lock lock(mx);
|
||||
vstd::copy_if(dArea.getTiles(), vstd::set_inserter(possibleTiles), [this](const int3 &tile) -> bool
|
||||
{
|
||||
return map.isPossible(tile);
|
||||
@ -201,6 +204,7 @@ void Zone::fractalize()
|
||||
rmg::Area tilesToIgnore; //will be erased in this iteration
|
||||
|
||||
const float minDistance = 10 * 10; //squared
|
||||
float blockDistance = minDistance * 0.25f;
|
||||
|
||||
if(type != ETemplateZoneType::JUNCTION)
|
||||
{
|
||||
@ -235,7 +239,7 @@ void Zone::fractalize()
|
||||
tilesToIgnore.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Lock lock(areaMutex);
|
||||
//cut straight paths towards the center. A* is too slow for that.
|
||||
auto areas = connectedAreas(clearedTiles, false);
|
||||
for(auto & area : areas)
|
||||
@ -264,7 +268,6 @@ void Zone::fractalize()
|
||||
}
|
||||
|
||||
//now block most distant tiles away from passages
|
||||
float blockDistance = minDistance * 0.25f;
|
||||
auto areaToBlock = dArea.getSubarea([this, blockDistance](const int3 & t)
|
||||
{
|
||||
auto distance = static_cast<float>(dAreaFree.distanceSqr(t));
|
||||
@ -272,6 +275,8 @@ void Zone::fractalize()
|
||||
});
|
||||
dAreaPossible.subtract(areaToBlock);
|
||||
dAreaFree.subtract(areaToBlock);
|
||||
|
||||
lock.unlock();
|
||||
for(const auto & t : areaToBlock.getTiles())
|
||||
map.setOccupied(t, ETileType::BLOCKED);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "../GameConstants.h"
|
||||
#include "float3.h"
|
||||
#include "../int3.h"
|
||||
#include "threadpool/JobProvider.h"
|
||||
#include "CRmgTemplate.h"
|
||||
#include "RmgArea.h"
|
||||
#include "RmgPath.h"
|
||||
@ -87,6 +86,10 @@ public:
|
||||
}
|
||||
|
||||
void initModificators();
|
||||
|
||||
public:
|
||||
boost::recursive_mutex areaMutex;
|
||||
using Lock = boost::unique_lock<boost::recursive_mutex>;
|
||||
|
||||
protected:
|
||||
CMapGenerator & generator;
|
||||
@ -106,7 +109,12 @@ protected:
|
||||
//template info
|
||||
si32 townType;
|
||||
TerrainId terrainType;
|
||||
|
||||
|
||||
/*
|
||||
private:
|
||||
mutable boost::shared_mutex mx; //Used for area access
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
*/
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* JobProvider.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "../../GameConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::function<void()> TRMGfunction ;
|
||||
typedef std::optional<TRMGfunction> TRMGJob;
|
||||
|
||||
class DLL_LINKAGE IJobProvider
|
||||
{
|
||||
public:
|
||||
//TODO: Think about some mutex protection
|
||||
|
||||
virtual TRMGJob getNextJob() = 0;
|
||||
virtual bool hasJobs() = 0;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
57
lib/rmg/threadpool/MapProxy.cpp
Normal file
57
lib/rmg/threadpool/MapProxy.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MapProxy.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MapProxy.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
MapProxy::MapProxy(RmgMap & map):
|
||||
map(map)
|
||||
{
|
||||
}
|
||||
|
||||
void MapProxy::insertObject(CGObjectInstance * obj)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->insertObject(obj);
|
||||
}
|
||||
|
||||
void MapProxy::insertObjects(std::set<CGObjectInstance*>& objects)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->insertObjects(objects);
|
||||
}
|
||||
|
||||
void MapProxy::drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawTerrain(terrain, &generator);
|
||||
}
|
||||
|
||||
void MapProxy::drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(terrain)->river, &generator);
|
||||
}
|
||||
|
||||
void MapProxy::drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawRoad(roadType, &generator);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
41
lib/rmg/threadpool/MapProxy.h
Normal file
41
lib/rmg/threadpool/MapProxy.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* MapProxy.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RmgMap;
|
||||
|
||||
class MapProxy
|
||||
{
|
||||
public:
|
||||
MapProxy(RmgMap & map);
|
||||
|
||||
void insertObject(CGObjectInstance * obj);
|
||||
void insertObjects(std::set<CGObjectInstance*>& objects);
|
||||
|
||||
void drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
|
||||
void drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
|
||||
void drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType);
|
||||
|
||||
private:
|
||||
mutable boost::shared_mutex mx;
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
|
||||
RmgMap & map;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -11,12 +11,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
#include "JobProvider.h"
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::function<void()> TRMGfunction ;
|
||||
typedef std::optional<TRMGfunction> TRMGJob;
|
||||
|
||||
//Credit to https://github.com/Liam0205/toy-threadpool/tree/master/yuuki
|
||||
|
||||
class DLL_LINKAGE ThreadPool
|
||||
|
@ -397,20 +397,24 @@ void MapController::commitObstacleFill(int level)
|
||||
return;
|
||||
|
||||
//split by zones
|
||||
std::map<TerrainId, ObstacleProxy> terrainSelected;
|
||||
|
||||
std::map<TerrainId, std::unique_ptr<EditorObstaclePlacer>> terrainSelected;
|
||||
for(auto & t : selection)
|
||||
{
|
||||
auto tl = _map->getTile(t);
|
||||
if(tl.blocked || tl.visitable)
|
||||
continue;
|
||||
|
||||
terrainSelected[tl.terType->getId()].blockedArea.add(t);
|
||||
auto terrain = tl.terType->getId();
|
||||
//FIXME: This map can be populated once at launch, not need to collect objects every time
|
||||
terrainSelected[terrain] = std::make_unique<EditorObstaclePlacer>(_map.get());
|
||||
terrainSelected[terrain]->addBlockedTile(t);
|
||||
}
|
||||
|
||||
for(auto & sel : terrainSelected)
|
||||
{
|
||||
sel.second.collectPossibleObstacles(sel.first);
|
||||
sel.second.placeObstacles(_map.get(), CRandomGenerator::getDefault());
|
||||
sel.second->collectPossibleObstacles(sel.first);
|
||||
sel.second->placeObstacles(CRandomGenerator::getDefault());
|
||||
}
|
||||
|
||||
_mapHandler->invalidateObjects();
|
||||
|
Loading…
Reference in New Issue
Block a user