From 559dde96cf591a51a0124e153b9c410bf4d71f69 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Mon, 27 Apr 2026 21:38:11 +0200 Subject: [PATCH] fix bug where buildings could not output directly on splitters --- src/lib/sim/BeltSystem.cpp | 15 ++++++++++++++- src/lib/sim/BeltSystem.h | 5 +++-- src/lib/sim/BuildingSystem.cpp | 2 +- src/test/BeltSystemTest.cpp | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/lib/sim/BeltSystem.cpp b/src/lib/sim/BeltSystem.cpp index 9d18416..78985ad 100644 --- a/src/lib/sim/BeltSystem.cpp +++ b/src/lib/sim/BeltSystem.cpp @@ -199,7 +199,7 @@ void BeltSystem::reevaluateTunnelPairing() // Port interface // --------------------------------------------------------------------------- -bool BeltSystem::tryPutItem(QPoint tile, Item item) +bool BeltSystem::tryPutItem(QPoint tile, Item item, Rotation fromDir) { const std::map, BeltTile>::iterator bIt = m_belts.find(key(tile)); if (bIt != m_belts.end()) @@ -207,6 +207,19 @@ bool BeltSystem::tryPutItem(QPoint tile, Item item) return tryPlaceOnBelt(tile, item); } + const std::map, SplitterTile>::iterator splIt = + m_splitters.find(key(tile)); + if (splIt != m_splitters.end()) + { + if (!splIt->second.back) + { + splIt->second.back = BeltItemSlot{item, 0.0}; + splIt->second.backDir = fromDir; + return true; + } + return false; + } + const std::map, TunnelEntryTile>::iterator teIt = m_tunnelEntries.find(key(tile)); if (teIt != m_tunnelEntries.end()) diff --git a/src/lib/sim/BeltSystem.h b/src/lib/sim/BeltSystem.h index 854ed89..126907f 100644 --- a/src/lib/sim/BeltSystem.h +++ b/src/lib/sim/BeltSystem.h @@ -72,8 +72,9 @@ public: // port.direction = direction items flow on that tile // // tryPutItem: place item onto tile. - // Returns false if the tile is not a belt, or tile full. - bool tryPutItem(QPoint tile, Item item); + // Returns false if the tile is not a belt/splitter, or tile full. + // fromDir: travel direction of the item (used for splitter animation). + bool tryPutItem(QPoint tile, Item item, Rotation fromDir = Rotation::West); // tryTakeItem: remove and return the leading item from port.tile. // Returns nullopt if tile is not a belt, direction mismatches, or tile empty. diff --git a/src/lib/sim/BuildingSystem.cpp b/src/lib/sim/BuildingSystem.cpp index b2ff9ff..1c8d8e3 100644 --- a/src/lib/sim/BuildingSystem.cpp +++ b/src/lib/sim/BuildingSystem.cpp @@ -713,7 +713,7 @@ void BuildingSystem::tickBeltPush() break; } const Item item = building.outputBuffer.items.front(); - if (m_belts.tryPutItem(outputPort.tile, item)) + if (m_belts.tryPutItem(outputPort.tile, item, outputPort.direction)) { building.outputBuffer.items.erase(building.outputBuffer.items.begin()); } diff --git a/src/test/BeltSystemTest.cpp b/src/test/BeltSystemTest.cpp index a01006d..7c1360a 100644 --- a/src/test/BeltSystemTest.cpp +++ b/src/test/BeltSystemTest.cpp @@ -629,6 +629,24 @@ TEST_CASE("BeltSystem: splitter accepts new items after building pulls from fron REQUIRE(bs.peekItem(Port{tileSpl, Rotation::South}).has_value()); } +TEST_CASE("BeltSystem: tryPutItem succeeds directly on a splitter tile", "[belt]") +{ + // Regression: buildings outputting onto a splitter tile were silently dropped + // because tryPutItem had no splitter case and returned false. + BeltSystem bs(kFastBeltSpeed); + + const QPoint tileSpl(0, 0); + bs.placeSplitter(tileSpl, Rotation::North, Rotation::South); + + REQUIRE(bs.tryPutItem(tileSpl, makeItem("iron_ore"), Rotation::East)); + + // Item should arrive at one of the output fronts after the splitter ticks through. + bs.tick(); // back advances to 0.5, routes to frontA + bs.tick(); // frontA reaches 1.0 + + REQUIRE(bs.peekItem(Port{tileSpl, Rotation::North}).has_value()); +} + TEST_CASE("BeltSystem: splitter alternates between two unregistered outputs (building inputs)", "[belt]") { BeltSystem bs(kFastBeltSpeed);