mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
Fix connections not getting actually updated
This commit is contained in:
@@ -290,7 +290,7 @@
|
|||||||
{ "a" : "16", "b" : "25", "guard" : 6000, "road" : "random" },
|
{ "a" : "16", "b" : "25", "guard" : 6000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "9", "b" : "10", "guard" : 6000, "road" : "true" },
|
{ "a" : "9", "b" : "10", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "9", "b" : "21", "guard" : 6000, "road" : "random" },
|
{ "a" : "9", "b" : "21", "guard" : 6000, "road" : "false" },
|
||||||
{ "a" : "9", "b" : "23", "guard" : 6000, "road" : "false" },
|
{ "a" : "9", "b" : "23", "guard" : 6000, "road" : "false" },
|
||||||
{ "a" : "10", "b" : "22", "guard" : 6000, "road" : "random" },
|
{ "a" : "10", "b" : "22", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "10", "b" : "23", "guard" : 6000, "road" : "random" },
|
{ "a" : "10", "b" : "23", "guard" : 6000, "road" : "random" },
|
||||||
@@ -298,7 +298,7 @@
|
|||||||
{ "a" : "13", "b" : "24", "guard" : 6000, "road" : "random" },
|
{ "a" : "13", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "13", "b" : "14", "guard" : 6000, "road" : "true" },
|
{ "a" : "13", "b" : "14", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "14", "b" : "23", "guard" : 6000, "road" : "false" },
|
{ "a" : "14", "b" : "23", "guard" : 6000, "road" : "false" },
|
||||||
{ "a" : "14", "b" : "25", "guard" : 6000, "road" : "random" },
|
{ "a" : "14", "b" : "25", "guard" : 6000, "road" : "false" },
|
||||||
|
|
||||||
{ "a" : "11", "b" : "21", "guard" : 6000, "road" : "true" },
|
{ "a" : "11", "b" : "21", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "11", "b" : "24", "guard" : 6000, "road" : "random" },
|
{ "a" : "11", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
|
|||||||
@@ -302,6 +302,28 @@ std::vector<ZoneConnection> ZoneOptions::getConnections() const
|
|||||||
return connectionDetails;
|
return connectionDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ZoneConnection>& ZoneOptions::getConnectionsRef()
|
||||||
|
{
|
||||||
|
return connectionDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneOptions::setRoadOption(int connectionId, rmg::ERoadOption roadOption)
|
||||||
|
{
|
||||||
|
for(auto & connection : connectionDetails)
|
||||||
|
{
|
||||||
|
if(connection.getId() == connectionId)
|
||||||
|
{
|
||||||
|
connection.setRoadOption(roadOption);
|
||||||
|
logGlobal->info("Set road option for connection %d between zones %d and %d to %s",
|
||||||
|
connectionId, connection.getZoneA(), connection.getZoneB(),
|
||||||
|
roadOption == rmg::ERoadOption::ROAD_TRUE ? "true" :
|
||||||
|
roadOption == rmg::ERoadOption::ROAD_FALSE ? "false" : "random");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logGlobal->warn("Failed to find connection with ID %d in zone %d", connectionId, id);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<TRmgTemplateZoneId> ZoneOptions::getConnectedZoneIds() const
|
std::vector<TRmgTemplateZoneId> ZoneOptions::getConnectedZoneIds() const
|
||||||
{
|
{
|
||||||
return connectedZoneIds;
|
return connectedZoneIds;
|
||||||
@@ -482,11 +504,21 @@ rmg::ERoadOption ZoneConnection::getRoadOption() const
|
|||||||
return hasRoad;
|
return hasRoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZoneConnection::setRoadOption(rmg::ERoadOption roadOption)
|
||||||
|
{
|
||||||
|
hasRoad = roadOption;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const ZoneConnection & l, const ZoneConnection & r)
|
bool operator==(const ZoneConnection & l, const ZoneConnection & r)
|
||||||
{
|
{
|
||||||
return l.id == r.id;
|
return l.id == r.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator<(const ZoneConnection & l, const ZoneConnection & r)
|
||||||
|
{
|
||||||
|
return l.id < r.id;
|
||||||
|
}
|
||||||
|
|
||||||
void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
|
void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
static const std::vector<std::string> connectionTypes =
|
static const std::vector<std::string> connectionTypes =
|
||||||
|
|||||||
@@ -105,10 +105,12 @@ public:
|
|||||||
int getGuardStrength() const;
|
int getGuardStrength() const;
|
||||||
rmg::EConnectionType getConnectionType() const;
|
rmg::EConnectionType getConnectionType() const;
|
||||||
rmg::ERoadOption getRoadOption() const;
|
rmg::ERoadOption getRoadOption() const;
|
||||||
|
void setRoadOption(rmg::ERoadOption roadOption);
|
||||||
|
|
||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler);
|
||||||
|
|
||||||
friend bool operator==(const ZoneConnection &, const ZoneConnection &);
|
friend bool operator==(const ZoneConnection &, const ZoneConnection &);
|
||||||
|
friend bool operator<(const ZoneConnection &, const ZoneConnection &);
|
||||||
private:
|
private:
|
||||||
int id;
|
int id;
|
||||||
TRmgTemplateZoneId zoneA;
|
TRmgTemplateZoneId zoneA;
|
||||||
@@ -185,8 +187,12 @@ public:
|
|||||||
|
|
||||||
void addConnection(const ZoneConnection & connection);
|
void addConnection(const ZoneConnection & connection);
|
||||||
std::vector<ZoneConnection> getConnections() const;
|
std::vector<ZoneConnection> getConnections() const;
|
||||||
|
std::vector<ZoneConnection>& getConnectionsRef();
|
||||||
std::vector<TRmgTemplateZoneId> getConnectedZoneIds() const;
|
std::vector<TRmgTemplateZoneId> getConnectedZoneIds() const;
|
||||||
|
|
||||||
|
// Set road option for a specific connection by ID
|
||||||
|
void setRoadOption(int connectionId, rmg::ERoadOption roadOption);
|
||||||
|
|
||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler);
|
||||||
|
|
||||||
EMonsterStrength::EMonsterStrength monsterStrength;
|
EMonsterStrength::EMonsterStrength monsterStrength;
|
||||||
|
|||||||
@@ -1008,13 +1008,15 @@ void CZonePlacer::assignZones(vstd::RNG * rand)
|
|||||||
void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
||||||
{
|
{
|
||||||
auto zones = map.getZones();
|
auto zones = map.getZones();
|
||||||
|
bool anyDropped;
|
||||||
|
|
||||||
//First, build a graph of road connections
|
do
|
||||||
|
{
|
||||||
|
anyDropped = false;
|
||||||
std::map<TRmgTemplateZoneId, std::set<TRmgTemplateZoneId>> roadGraph;
|
std::map<TRmgTemplateZoneId, std::set<TRmgTemplateZoneId>> roadGraph;
|
||||||
std::vector<rmg::ZoneConnection> randomConnections;
|
std::set<rmg::ZoneConnection> randomConnections;
|
||||||
std::vector<rmg::ZoneConnection> fixedConnections;
|
|
||||||
|
|
||||||
//Collect all road connections and build initial graph
|
//Build graph and collect random connections
|
||||||
for(const auto & zone : zones)
|
for(const auto & zone : zones)
|
||||||
{
|
{
|
||||||
for(const auto & connection : zone.second->getConnections())
|
for(const auto & connection : zone.second->getConnections())
|
||||||
@@ -1023,84 +1025,61 @@ void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
|||||||
{
|
{
|
||||||
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
||||||
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
||||||
fixedConnections.push_back(connection);
|
|
||||||
}
|
}
|
||||||
else if(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM)
|
else if(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM)
|
||||||
{
|
{
|
||||||
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
||||||
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
||||||
randomConnections.push_back(connection);
|
randomConnections.insert(connection);
|
||||||
}
|
}
|
||||||
|
// ROAD_FALSE connections are ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logGlobal->info("Remaining random connections: %d", randomConnections.size());
|
||||||
|
|
||||||
//Find all connected components in the initial graph
|
if(randomConnections.empty())
|
||||||
std::map<TRmgTemplateZoneId, int> zoneToComponent;
|
break;
|
||||||
int numComponents = 0;
|
|
||||||
|
|
||||||
auto dfsComponent = [&](TRmgTemplateZoneId start, int component)
|
//Convert to vector for shuffling
|
||||||
|
std::vector<rmg::ZoneConnection> shuffledConnections(randomConnections.begin(), randomConnections.end());
|
||||||
|
RandomGeneratorUtil::randomShuffle(shuffledConnections, *rand);
|
||||||
|
|
||||||
|
//Try each random connection in shuffled order
|
||||||
|
for(const auto & conn : shuffledConnections)
|
||||||
{
|
{
|
||||||
std::stack<TRmgTemplateZoneId> stack;
|
auto zoneA = conn.getZoneA();
|
||||||
stack.push(start);
|
auto zoneB = conn.getZoneB();
|
||||||
|
|
||||||
while(!stack.empty())
|
//Check if either zone would become isolated by removing this connection
|
||||||
|
if(roadGraph[zoneA].size() <= 1 || roadGraph[zoneB].size() <= 1)
|
||||||
{
|
{
|
||||||
auto current = stack.top();
|
//Can't remove this connection as it would isolate a zone
|
||||||
stack.pop();
|
|
||||||
|
|
||||||
if(zoneToComponent.find(current) != zoneToComponent.end())
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
zoneToComponent[current] = component;
|
|
||||||
|
|
||||||
for(auto neighbor : roadGraph[current])
|
|
||||||
{
|
|
||||||
if(zoneToComponent.find(neighbor) == zoneToComponent.end())
|
|
||||||
{
|
|
||||||
stack.push(neighbor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Find all components
|
|
||||||
for(const auto & zone : zones)
|
|
||||||
{
|
|
||||||
if(zoneToComponent.find(zone.first) == zoneToComponent.end() && !roadGraph[zone.first].empty())
|
|
||||||
{
|
|
||||||
dfsComponent(zone.first, numComponents++);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Process each component separately
|
|
||||||
for(int component = 0; component < numComponents; component++)
|
|
||||||
{
|
|
||||||
//Get random connections for this component
|
|
||||||
std::vector<rmg::ZoneConnection> componentRandomConnections;
|
|
||||||
for(const auto & conn : randomConnections)
|
|
||||||
{
|
|
||||||
if(zoneToComponent[conn.getZoneA()] == component)
|
|
||||||
{
|
|
||||||
componentRandomConnections.push_back(conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Shuffle random connections
|
|
||||||
RandomGeneratorUtil::randomShuffle(componentRandomConnections, *rand);
|
|
||||||
|
|
||||||
//Try removing each random connection
|
|
||||||
for(const auto & conn : componentRandomConnections)
|
|
||||||
{
|
|
||||||
//Temporarily remove this connection
|
//Temporarily remove this connection
|
||||||
roadGraph[conn.getZoneA()].erase(conn.getZoneB());
|
roadGraph[zoneA].erase(zoneB);
|
||||||
roadGraph[conn.getZoneB()].erase(conn.getZoneA());
|
roadGraph[zoneB].erase(zoneA);
|
||||||
|
|
||||||
//Check if graph remains connected
|
//Check if graph remains connected as a whole
|
||||||
bool canRemove = true;
|
bool canRemove = true;
|
||||||
std::set<TRmgTemplateZoneId> visited;
|
std::set<TRmgTemplateZoneId> visited;
|
||||||
|
|
||||||
//Start DFS from any zone in this component
|
// Get all zones that have road connections
|
||||||
auto startZone = conn.getZoneA();
|
std::set<TRmgTemplateZoneId> zonesWithRoads;
|
||||||
|
for(const auto & entry : roadGraph)
|
||||||
|
{
|
||||||
|
if(!entry.second.empty())
|
||||||
|
{
|
||||||
|
zonesWithRoads.insert(entry.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!zonesWithRoads.empty())
|
||||||
|
{
|
||||||
|
//Start DFS from any zone that has roads
|
||||||
|
TRmgTemplateZoneId startZone = *zonesWithRoads.begin();
|
||||||
|
|
||||||
std::stack<TRmgTemplateZoneId> stack;
|
std::stack<TRmgTemplateZoneId> stack;
|
||||||
stack.push(startZone);
|
stack.push(startZone);
|
||||||
|
|
||||||
@@ -1123,12 +1102,10 @@ void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if all zones in this component are still reachable
|
//Check if all zones with roads are still reachable
|
||||||
for(const auto & zone : zones)
|
for(auto zoneId : zonesWithRoads)
|
||||||
{
|
{
|
||||||
if(zoneToComponent[zone.first] == component && !roadGraph[zone.first].empty())
|
if(visited.find(zoneId) == visited.end())
|
||||||
{
|
|
||||||
if(visited.find(zone.first) == visited.end())
|
|
||||||
{
|
{
|
||||||
canRemove = false;
|
canRemove = false;
|
||||||
break;
|
break;
|
||||||
@@ -1138,24 +1115,44 @@ void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
|||||||
|
|
||||||
if(!canRemove)
|
if(!canRemove)
|
||||||
{
|
{
|
||||||
//Restore connection if removing it would break connectivity
|
//Restore connection and try next one
|
||||||
roadGraph[conn.getZoneA()].insert(conn.getZoneB());
|
roadGraph[zoneA].insert(zoneB);
|
||||||
roadGraph[conn.getZoneB()].insert(conn.getZoneA());
|
roadGraph[zoneB].insert(zoneA);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
//Found a connection we can remove - update in both zones that contain it
|
||||||
//Mark this connection as having no road
|
auto & zonePtr = zones[zoneA];
|
||||||
|
zonePtr->setRoadOption(conn.getId(), rmg::ERoadOption::ROAD_FALSE);
|
||||||
|
|
||||||
|
auto & otherZonePtr = zones[zoneB];
|
||||||
|
otherZonePtr->setRoadOption(conn.getId(), rmg::ERoadOption::ROAD_FALSE);
|
||||||
|
|
||||||
|
logGlobal->info("Dropped random road between %d and %d", zoneA, zoneB);
|
||||||
|
anyDropped = true;
|
||||||
|
break; //Exit loop and rebuild graph
|
||||||
|
}
|
||||||
|
} while(anyDropped);
|
||||||
|
|
||||||
|
// Use a set to track processed connection IDs to avoid duplicates
|
||||||
|
std::set<int> processedConnectionIds;
|
||||||
|
|
||||||
|
// Process each zone's connections
|
||||||
for(auto & zonePtr : zones)
|
for(auto & zonePtr : zones)
|
||||||
{
|
{
|
||||||
for(auto & connection : zonePtr.second->getConnections())
|
for(auto & connection : zonePtr.second->getConnections())
|
||||||
{
|
{
|
||||||
if(connection.getId() == conn.getId())
|
if(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM)
|
||||||
{
|
{
|
||||||
const_cast<rmg::ZoneConnection&>(connection) = conn; //FIXME: avoid const_cast
|
auto id = connection.getId();
|
||||||
break;
|
// Only process each connection once
|
||||||
}
|
if(vstd::contains(processedConnectionIds, id))
|
||||||
}
|
continue;
|
||||||
}
|
|
||||||
|
processedConnectionIds.insert(id);
|
||||||
|
|
||||||
|
// Use the new setRoadOption method
|
||||||
|
zonePtr.second->setRoadOption(id, rmg::ERoadOption::ROAD_TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,15 +110,11 @@ void ConnectionsPlacer::init()
|
|||||||
POSTFUNCTION(RoadPlacer);
|
POSTFUNCTION(RoadPlacer);
|
||||||
POSTFUNCTION(ObjectManager);
|
POSTFUNCTION(ObjectManager);
|
||||||
|
|
||||||
auto id = zone.getId();
|
// FIXME: Use zones modified by CZonePlacer
|
||||||
for(auto c : map.getMapGenOptions().getMapTemplate()->getConnectedZoneIds())
|
for (auto c : zone.getConnections())
|
||||||
{
|
|
||||||
// Only consider connected zones
|
|
||||||
if (c.getZoneA() == id || c.getZoneB() == id)
|
|
||||||
{
|
{
|
||||||
addConnection(c);
|
addConnection(c);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsPlacer::addConnection(const rmg::ZoneConnection& connection)
|
void ConnectionsPlacer::addConnection(const rmg::ZoneConnection& connection)
|
||||||
@@ -477,6 +473,10 @@ void ConnectionsPlacer::collectNeighbourZones()
|
|||||||
|
|
||||||
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
|
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
|
||||||
{
|
{
|
||||||
|
if (connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM)
|
||||||
|
logGlobal->error("Random road between zones %d and %d", connection.getZoneA(), connection.getZoneB());
|
||||||
|
else
|
||||||
|
logGlobal->info("Should generate road between zones %d and %d: %d", connection.getZoneA(), connection.getZoneB(), connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE);
|
||||||
return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE;
|
return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user