fix splitter filters being lost when rotating in place
rotateInPlace re-implemented the belt-tile re-registration switch inline instead of calling reregisterBeltTile, and its splitter branch omitted the setSplitterFilters call the canonical version has. Since an operational splitter keeps its filters only in BeltSystem, removeTile discarded them and rotating a configured splitter silently reset it to "accept all". Replace the duplicated switch with a call to reregisterBeltTile, capturing the filters beforehand via getSplitterInfo — the same idiom deconstruct already uses. This removes the second copy of the switch that allowed the two to drift apart in the first place. Add a regression test; the existing [rotate-in-place] cases covered belt tiles only, which is why this went unnoticed. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
This commit is contained in:
@@ -1719,29 +1719,25 @@ void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
|||||||
// the new port set (REQ-MAT-INPUT-INTAKE).
|
// the new port set (REQ-MAT-INPUT-INTAKE).
|
||||||
b.incomingItems.assign(b.inputPorts.size(), {});
|
b.incomingItems.assign(b.inputPorts.size(), {});
|
||||||
|
|
||||||
// Re-register with BeltSystem (items on tile are discarded).
|
// Re-register with BeltSystem (items on tile are discarded). A splitter's
|
||||||
if (b.type == BuildingType::Belt)
|
// filters live in BeltSystem and would be lost by removeTile, so capture
|
||||||
|
// them first and hand them back to reregisterBeltTile (REQ-BLD-SPLITTER).
|
||||||
|
if (isBeltSubsystemType(b.type))
|
||||||
{
|
{
|
||||||
m_belts.removeTile(b.anchor);
|
std::vector<ItemType> splitterFilterA;
|
||||||
m_belts.placeBelt(b.anchor, newRotation);
|
std::vector<ItemType> splitterFilterB;
|
||||||
|
if (b.type == BuildingType::Splitter)
|
||||||
|
{
|
||||||
|
if (const std::optional<BeltSystem::SplitterInfo> info =
|
||||||
|
m_belts.getSplitterInfo(b.anchor))
|
||||||
|
{
|
||||||
|
splitterFilterA = info->filterA;
|
||||||
|
splitterFilterB = info->filterB;
|
||||||
}
|
}
|
||||||
else if (b.type == BuildingType::Splitter)
|
|
||||||
{
|
|
||||||
m_belts.removeTile(b.anchor);
|
|
||||||
assert(mask.outputPorts.size() >= 2);
|
|
||||||
m_belts.placeSplitter(b.anchor,
|
|
||||||
mask.outputPorts[0].direction,
|
|
||||||
mask.outputPorts[1].direction);
|
|
||||||
}
|
}
|
||||||
else if (b.type == BuildingType::TunnelEntry)
|
|
||||||
{
|
|
||||||
m_belts.removeTile(b.anchor);
|
m_belts.removeTile(b.anchor);
|
||||||
m_belts.placeTunnelEntry(b.anchor, newRotation, m_config.world.tunnelMaxDistance_tiles);
|
reregisterBeltTile(b, splitterFilterA, splitterFilterB);
|
||||||
}
|
|
||||||
else if (b.type == BuildingType::TunnelExit)
|
|
||||||
{
|
|
||||||
m_belts.removeTile(b.anchor);
|
|
||||||
m_belts.placeTunnelExit(b.anchor, newRotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1427,6 +1427,36 @@ TEST_CASE("BuildingSystem: rotateInPlace re-registers a belt tile with BeltSyste
|
|||||||
REQUIRE(belts.tryPutItem(QPoint(0, 0), makeItem("iron_ore")));
|
REQUIRE(belts.tryPutItem(QPoint(0, 0), makeItem("iron_ore")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BuildingSystem: rotateInPlace preserves the output filters of a splitter "
|
||||||
|
"(REQ-BLD-SPLITTER)", "[building][rotate-in-place]")
|
||||||
|
{
|
||||||
|
PlacementFixture f;
|
||||||
|
|
||||||
|
const QPoint tile(5, 5);
|
||||||
|
const BuildingId id = f.bs.place(BuildingType::Splitter, tile, Rotation::East, 0).value();
|
||||||
|
|
||||||
|
// Run until construction completes, so the splitter is registered with BeltSystem.
|
||||||
|
Tick tick = 0;
|
||||||
|
while (f.bs.getAllBuildings().empty() && tick < 100000)
|
||||||
|
{
|
||||||
|
runTicks(f.bs, f.belts, 1, tick);
|
||||||
|
}
|
||||||
|
REQUIRE(f.bs.getAllBuildings().size() == 1);
|
||||||
|
|
||||||
|
const std::vector<ItemType> filterA{ ItemType{"iron_ore"} };
|
||||||
|
const std::vector<ItemType> filterB{ ItemType{"copper_ore"} };
|
||||||
|
f.belts.setSplitterFilters(tile, filterA, filterB);
|
||||||
|
|
||||||
|
f.bs.rotateInPlace(id, Rotation::North);
|
||||||
|
|
||||||
|
// The tile is re-registered with BeltSystem carrying the filters it had before
|
||||||
|
// the rotation — rotating must not reset a configured splitter to "accept all".
|
||||||
|
const std::optional<BeltSystem::SplitterInfo> info = f.belts.getSplitterInfo(tile);
|
||||||
|
REQUIRE(info.has_value());
|
||||||
|
REQUIRE(info->filterA == filterA);
|
||||||
|
REQUIRE(info->filterB == filterB);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("BuildingSystem: splitter filters configured on a construction site carry over "
|
TEST_CASE("BuildingSystem: splitter filters configured on a construction site carry over "
|
||||||
"to the built splitter (REQ-BLD-SITE-CONFIG)", "[building]")
|
"to the built splitter (REQ-BLD-SITE-CONFIG)", "[building]")
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user