diff --git a/server/src/board/map/blockpath.cpp b/server/src/board/map/blockpath.cpp index f1a57d5e..079b703d 100644 --- a/server/src/board/map/blockpath.cpp +++ b/server/src/board/map/blockpath.cpp @@ -34,6 +34,7 @@ #include "../tile/rail/linkrailtile.hpp" #include "../tile/rail/nxbuttonrailtile.hpp" #include "../../train/trainblockstatus.hpp" +#include "../../core/eventloop.hpp" #include "../../core/objectproperty.tpp" #include "../../enum/bridgepath.hpp" @@ -297,10 +298,34 @@ BlockPath::BlockPath(BlockRailTile& block, BlockSide side) : m_fromBlock{block} , m_fromSide{side} , m_toSide{static_cast(-1)} + , m_delayReleaseTimer{EventLoop::ioContext} , m_isReserved(false) + , m_delayedReleaseScheduled(false) { } +BlockPath::BlockPath(const BlockPath &other) + : Path(other) + , std::enable_shared_from_this() + , m_fromBlock(other.m_fromBlock) + , m_fromSide(other.m_fromSide) + , m_toBlock(other.m_toBlock) + , m_toSide(other.m_toSide) + , m_tiles(other.m_tiles) + , m_turnouts(other.m_turnouts) + , m_directionControls(other.m_directionControls) + , m_crossings(other.m_crossings) + , m_bridges(other.m_bridges) + , m_signals(other.m_signals) + , m_nxButtonFrom(other.m_nxButtonFrom) + , m_nxButtonTo(other.m_nxButtonTo) + , m_delayReleaseTimer{EventLoop::ioContext} + , m_isReserved(false) + , m_delayedReleaseScheduled(false) +{ + +} + bool BlockPath::operator ==(const BlockPath& other) const noexcept { return @@ -504,6 +529,9 @@ bool BlockPath::release(bool dryRun) return false; } + if(!dryRun) + m_delayReleaseTimer.cancel(); + auto toBlock = m_toBlock.lock(); if(!toBlock) /*[[unlikely]]*/ return false; @@ -629,3 +657,23 @@ bool BlockPath::release(bool dryRun) return true; } + +bool BlockPath::delayedRelease(uint16_t timeoutMillis) +{ + if(m_delayedReleaseScheduled) + return false; + + m_delayedReleaseScheduled = true; + + m_delayReleaseTimer.expires_after(boost::asio::chrono::milliseconds(timeoutMillis)); + m_delayReleaseTimer.async_wait([this](const boost::system::error_code& ec) + { + m_delayedReleaseScheduled = false; + + if(ec) + return; + + release(); + }); + return true; +} diff --git a/server/src/board/map/blockpath.hpp b/server/src/board/map/blockpath.hpp index 80982f68..623e9451 100644 --- a/server/src/board/map/blockpath.hpp +++ b/server/src/board/map/blockpath.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "../../enum/blockside.hpp" class RailTile; @@ -63,12 +64,16 @@ class BlockPath : public Path, public std::enable_shared_from_this std::vector> m_signals; //!< signals in path std::weak_ptr m_nxButtonFrom; std::weak_ptr m_nxButtonTo; + + boost::asio::steady_timer m_delayReleaseTimer; bool m_isReserved; + bool m_delayedReleaseScheduled; public: static std::vector> find(BlockRailTile& block); BlockPath(BlockRailTile& block, BlockSide side); + BlockPath(const BlockPath& other); bool operator ==(const BlockPath& other) const noexcept; @@ -110,6 +115,7 @@ class BlockPath : public Path, public std::enable_shared_from_this bool reserve(const std::shared_ptr& train, bool dryRun = false); bool release(bool dryRun = false); + bool delayedRelease(uint16_t timeoutMillis); }; #endif diff --git a/server/src/board/tile/rail/blockrailtile.cpp b/server/src/board/tile/rail/blockrailtile.cpp index e96c49df..a400462c 100644 --- a/server/src/board/tile/rail/blockrailtile.cpp +++ b/server/src/board/tile/rail/blockrailtile.cpp @@ -335,11 +335,11 @@ void BlockRailTile::inputItemValueChanged(BlockInputMapItem& item) if(blockTrainDirection == BlockTrainDirection::TowardsA && exitA) { - pathA->release(); + pathA->delayedRelease(m_world.pathReleaseDelay); } else if(blockTrainDirection == BlockTrainDirection::TowardsB && exitB) { - pathB->release(); + pathB->delayedRelease(m_world.pathReleaseDelay); } } } diff --git a/server/src/world/world.cpp b/server/src/world/world.cpp index b7d8b5fd..2dc71297 100644 --- a/server/src/world/world.cpp +++ b/server/src/world/world.cpp @@ -147,6 +147,7 @@ World::World(Private /*unused*/) : }}, correctOutputPosWhenLocked{this, "correct_output_pos_when_locked", true, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript}, extOutputChangeAction{this, "ext_output_change_action", ExternalOutputChangeAction::EmergencyStopTrain, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript}, + pathReleaseDelay{this, "path_release_delay", 5000, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript}, decoderControllers{this, "input_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore}, inputControllers{this, "input_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore}, outputControllers{this, "output_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore}, @@ -320,6 +321,11 @@ World::World(Private /*unused*/) : Attributes::addValues(extOutputChangeAction, extOutputChangeActionValues); m_interfaceItems.add(extOutputChangeAction); + Attributes::addCategory(pathReleaseDelay, Category::trains); + Attributes::addEnabled(pathReleaseDelay, true); + Attributes::addMinMax(pathReleaseDelay, {0, 15000}); // Up to 15 seconds + m_interfaceItems.add(pathReleaseDelay); + Attributes::addObjectEditor(decoderControllers, false); m_interfaceItems.add(decoderControllers); Attributes::addObjectEditor(inputControllers, false); diff --git a/server/src/world/world.hpp b/server/src/world/world.hpp index cf73e8ce..d2dbdad9 100644 --- a/server/src/world/world.hpp +++ b/server/src/world/world.hpp @@ -106,6 +106,7 @@ class World : public Object Property correctOutputPosWhenLocked; Property extOutputChangeAction; + Property pathReleaseDelay; ObjectProperty> decoderControllers; ObjectProperty> inputControllers; diff --git a/shared/translations/en-us.json b/shared/translations/en-us.json index c5194455..487d04a8 100644 --- a/shared/translations/en-us.json +++ b/shared/translations/en-us.json @@ -4502,6 +4502,14 @@ "reference": "", "comment": "" }, + { + "term": "world:path_release_delay", + "definition": "Block Path release delay", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, { "term": "world_scale:custom", "definition": "Custom", diff --git a/shared/translations/it-it.json b/shared/translations/it-it.json index 15a02bc0..a733b734 100644 --- a/shared/translations/it-it.json +++ b/shared/translations/it-it.json @@ -4502,6 +4502,14 @@ "reference": "", "comment": "" }, + { + "term": "world:path_release_delay", + "definition": "Ritardo nella liberazione dell'itinerario", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, { "term": "world_scale:custom", "definition": "Custom",