signaling: improved 3 aspect signal
signal is now aware of next signal aspect
Dieser Commit ist enthalten in:
Ursprung
12e23c90a9
Commit
5c69cb107d
@ -84,6 +84,36 @@ bool AbstractSignalPath::requireReservation() const
|
||||
return (m_signal.requireReservation == AutoYesNo::Yes || (m_signal.requireReservation == AutoYesNo::Auto && m_requireReservation));
|
||||
}
|
||||
|
||||
const AbstractSignalPath::BlockItem* AbstractSignalPath::nextBlock(const Item* item) const
|
||||
{
|
||||
while(item)
|
||||
{
|
||||
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
|
||||
{
|
||||
return blockItem;
|
||||
}
|
||||
item = item->next().get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::tuple<const AbstractSignalPath::BlockItem*, const AbstractSignalPath::SignalItem*> AbstractSignalPath::nextBlockOrSignal(const Item* item) const
|
||||
{
|
||||
while(item)
|
||||
{
|
||||
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
|
||||
{
|
||||
return {blockItem, nullptr};
|
||||
}
|
||||
if(const auto* signalItem = dynamic_cast<const SignalItem*>(item))
|
||||
{
|
||||
return {nullptr, signalItem};
|
||||
}
|
||||
item = item->next().get();
|
||||
}
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
void AbstractSignalPath::getBlockStates(tcb::span<BlockState> blockStates) const
|
||||
{
|
||||
size_t i = 0;
|
||||
@ -135,13 +165,30 @@ std::unique_ptr<const AbstractSignalPath::Item> AbstractSignalPath::findBlocks(c
|
||||
evaluate();
|
||||
}));
|
||||
|
||||
const auto enterSide = (nextNode.getLink(0).get() == &link) ? BlockSide::A : BlockSide::B;
|
||||
std::unique_ptr<const Item> next;
|
||||
if(blocksAhead > 1)
|
||||
if(const auto& nextLink = otherLink(nextNode, link))
|
||||
next = findBlocks(nextNode, *nextLink, blocksAhead - 1);
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{new BlockItem(block, std::move(next))};
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{new BlockItem(block, enterSide, std::move(next))};
|
||||
}
|
||||
if(auto turnout = std::dynamic_pointer_cast<TurnoutRailTile>(tile))
|
||||
if(auto signal = std::dynamic_pointer_cast<SignalRailTile>(tile))
|
||||
{
|
||||
if(const auto& nextLink = otherLink(nextNode, link))
|
||||
{
|
||||
m_connections.emplace_back(signal->aspectChanged.connect(
|
||||
[this](const SignalRailTile& /*tile*/, SignalAspect /*aspect*/)
|
||||
{
|
||||
evaluate();
|
||||
}));
|
||||
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{
|
||||
new SignalItem(
|
||||
signal,
|
||||
findBlocks(nextNode, *nextLink, blocksAhead))};
|
||||
}
|
||||
}
|
||||
else if(auto turnout = std::dynamic_pointer_cast<TurnoutRailTile>(tile))
|
||||
{
|
||||
m_connections.emplace_back(turnout->positionChanged.connect(
|
||||
[this](const TurnoutRailTile& /*tile*/, TurnoutPosition /*position*/)
|
||||
|
||||
@ -20,8 +20,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef TRAINTASTIC_SERVER_BOARD_MAP_SIGNALPATH_HPP
|
||||
#define TRAINTASTIC_SERVER_BOARD_MAP_SIGNALPATH_HPP
|
||||
#ifndef TRAINTASTIC_SERVER_BOARD_MAP_ABSTRACTSIGNALPATH_HPP
|
||||
#define TRAINTASTIC_SERVER_BOARD_MAP_ABSTRACTSIGNALPATH_HPP
|
||||
|
||||
#include "path.hpp"
|
||||
#include "link.hpp"
|
||||
@ -30,6 +30,7 @@
|
||||
#include <traintastic/enum/blockstate.hpp>
|
||||
|
||||
class BlockRailTile;
|
||||
enum class BlockSide : uint8_t;
|
||||
class TurnoutRailTile;
|
||||
enum class TurnoutPosition : uint8_t;
|
||||
class DirectionControlRailTile;
|
||||
@ -47,7 +48,7 @@ class AbstractSignalPath : public Path
|
||||
|
||||
void setAspect(SignalAspect value) const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
class Item
|
||||
{
|
||||
private:
|
||||
@ -69,11 +70,13 @@ class AbstractSignalPath : public Path
|
||||
{
|
||||
private:
|
||||
std::weak_ptr<BlockRailTile> m_block;
|
||||
BlockSide m_enterSide;
|
||||
std::unique_ptr<const Item> m_next;
|
||||
|
||||
public:
|
||||
BlockItem(std::weak_ptr<BlockRailTile> block, std::unique_ptr<const Item> next_)
|
||||
BlockItem(std::weak_ptr<BlockRailTile> block, BlockSide enterSide_, std::unique_ptr<const Item> next_)
|
||||
: m_block{std::move(block)}
|
||||
, m_enterSide{enterSide_}
|
||||
, m_next{std::move(next_)}
|
||||
{
|
||||
}
|
||||
@ -85,6 +88,34 @@ class AbstractSignalPath : public Path
|
||||
|
||||
std::shared_ptr<BlockRailTile> block() const noexcept;
|
||||
BlockState blockState() const;
|
||||
BlockSide enterSide() const
|
||||
{
|
||||
return m_enterSide;
|
||||
}
|
||||
};
|
||||
|
||||
class SignalItem : public Item
|
||||
{
|
||||
private:
|
||||
std::weak_ptr<SignalRailTile> m_signal;
|
||||
std::unique_ptr<const Item> m_next;
|
||||
|
||||
public:
|
||||
SignalItem(std::weak_ptr<SignalRailTile> signal, std::unique_ptr<const Item> next_)
|
||||
: m_signal{std::move(signal)}
|
||||
, m_next{std::move(next_)}
|
||||
{
|
||||
}
|
||||
|
||||
const std::unique_ptr<const Item>& next() const final
|
||||
{
|
||||
return m_next;
|
||||
}
|
||||
|
||||
std::shared_ptr<SignalRailTile> signal() const
|
||||
{
|
||||
return m_signal.lock();
|
||||
}
|
||||
};
|
||||
|
||||
class TurnoutItem : public Item
|
||||
@ -121,6 +152,7 @@ class AbstractSignalPath : public Path
|
||||
const std::unique_ptr<const Item>& next() const final;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<const Item> m_root;
|
||||
bool m_requireReservation = false;
|
||||
std::vector<boost::signals2::connection> m_connections;
|
||||
@ -144,6 +176,23 @@ class AbstractSignalPath : public Path
|
||||
|
||||
virtual SignalAspect determineAspect() const = 0;
|
||||
|
||||
const Item* root() const
|
||||
{
|
||||
return m_root.get();
|
||||
}
|
||||
|
||||
const BlockItem* nextBlock(const Item* item) const;
|
||||
inline const BlockItem* nextBlock() const
|
||||
{
|
||||
return nextBlock(root());
|
||||
}
|
||||
|
||||
std::tuple<const BlockItem*, const SignalItem*> nextBlockOrSignal(const Item* item) const;
|
||||
inline std::tuple<const BlockItem*, const SignalItem*> nextBlockOrSignal() const
|
||||
{
|
||||
return nextBlockOrSignal(root());
|
||||
}
|
||||
|
||||
void getBlockStates(tcb::span<BlockState> blockStates) const;
|
||||
std::shared_ptr<BlockRailTile> getBlock(size_t index) const;
|
||||
|
||||
|
||||
@ -310,7 +310,7 @@ bool BlockPath::reserve(const std::shared_ptr<Train>& train, bool dryRun)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_fromBlock.reserve(train, m_fromSide, dryRun))
|
||||
if(!m_fromBlock.reserve(shared_from_this(), train, m_fromSide, dryRun))
|
||||
{
|
||||
assert(dryRun);
|
||||
return false;
|
||||
@ -318,7 +318,7 @@ bool BlockPath::reserve(const std::shared_ptr<Train>& train, bool dryRun)
|
||||
|
||||
if(auto toBlock = m_toBlock.lock()) /*[[likely]]*/
|
||||
{
|
||||
if(!toBlock->reserve(train, m_toSide, dryRun))
|
||||
if(!toBlock->reserve(shared_from_this(), train, m_toSide, dryRun))
|
||||
{
|
||||
assert(dryRun);
|
||||
return false;
|
||||
|
||||
@ -271,7 +271,13 @@ void BlockRailTile::identificationEvent(BlockInputMapItem& /*item*/, Identificat
|
||||
}
|
||||
}
|
||||
|
||||
bool BlockRailTile::reserve(const std::shared_ptr<Train>& train, BlockSide side, bool dryRun)
|
||||
const std::shared_ptr<BlockPath> BlockRailTile::getReservedPath(BlockSide side) const
|
||||
{
|
||||
assert(side == BlockSide::A || side == BlockSide::B);
|
||||
return m_reservedPaths[static_cast<uint8_t>(side)].lock();
|
||||
}
|
||||
|
||||
bool BlockRailTile::reserve(const std::shared_ptr<BlockPath>& blockPath, const std::shared_ptr<Train>& train, BlockSide side, bool dryRun)
|
||||
{
|
||||
const uint8_t mask = 1 << static_cast<uint8_t>(side);
|
||||
|
||||
@ -308,6 +314,7 @@ bool BlockRailTile::reserve(const std::shared_ptr<Train>& train, BlockSide side,
|
||||
|
||||
if(!dryRun)
|
||||
{
|
||||
m_reservedPaths[static_cast<uint8_t>(side)] = blockPath;
|
||||
RailTile::reserve(reservedState() | mask);
|
||||
if(state == BlockState::Free)
|
||||
{
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#define TRAINTASTIC_SERVER_BOARD_TILE_RAIL_BLOCKRAILTILE_HPP
|
||||
|
||||
#include "railtile.hpp"
|
||||
#include <array>
|
||||
#include <traintastic/enum/blocktraindirection.hpp>
|
||||
#include "../../map/node.hpp"
|
||||
#include "../../../core/method.hpp"
|
||||
@ -47,6 +48,7 @@ class BlockRailTile : public RailTile
|
||||
private:
|
||||
Node m_node;
|
||||
std::vector<std::shared_ptr<BlockPath>> m_paths;
|
||||
std::array<std::weak_ptr<BlockPath>, 2> m_reservedPaths; // index is BlockSide
|
||||
|
||||
void updateHeightWidthMax();
|
||||
|
||||
@ -90,7 +92,8 @@ class BlockRailTile : public RailTile
|
||||
void inputItemValueChanged(BlockInputMapItem& item);
|
||||
void identificationEvent(BlockInputMapItem& item, IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t category);
|
||||
|
||||
bool reserve(const std::shared_ptr<Train>& train, BlockSide side, bool dryRun = false);
|
||||
const std::shared_ptr<BlockPath> getReservedPath(BlockSide side) const;
|
||||
bool reserve(const std::shared_ptr<BlockPath>& blockPath, const std::shared_ptr<Train>& train, BlockSide side, bool dryRun = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "signal3aspectrailtile.hpp"
|
||||
#include "../blockrailtile.hpp"
|
||||
#include "../../../map/abstractsignalpath.hpp"
|
||||
#include "../../../map/blockpath.hpp"
|
||||
#include "../../../../core/attributes.hpp"
|
||||
@ -34,30 +35,65 @@ namespace
|
||||
{
|
||||
class SignalPath : public AbstractSignalPath
|
||||
{
|
||||
private:
|
||||
static bool hasSignalReservedPathToBlock(const SignalRailTile& signalTile, const BlockRailTile& blockTile)
|
||||
{
|
||||
const auto path = signalTile.reservedPath();
|
||||
return path && path->toBlock().get() == &blockTile;
|
||||
}
|
||||
|
||||
static bool isPathReserved(const BlockRailTile& from, BlockSide fromSide, const BlockRailTile& to)
|
||||
{
|
||||
if(const auto path = from.getReservedPath(fromSide))
|
||||
{
|
||||
return (&to == path->toBlock().get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
SignalAspect determineAspect() const final
|
||||
{
|
||||
std::array<BlockState, 2> states;
|
||||
getBlockStates(states);
|
||||
|
||||
if(!requireReservation() && states[0] == BlockState::Free)
|
||||
const auto* blockItem = nextBlock();
|
||||
if(!blockItem)
|
||||
{
|
||||
if(states[1] == BlockState::Free)
|
||||
return SignalAspect::Stop;
|
||||
}
|
||||
const auto blockState = blockItem->blockState();
|
||||
|
||||
if((!requireReservation() && blockState == BlockState::Free) ||
|
||||
(blockState == BlockState::Reserved && hasSignalReservedPathToBlock(signal(), *blockItem->block())))
|
||||
{
|
||||
auto [blockItem2, signalItem2] = nextBlockOrSignal(blockItem->next().get());
|
||||
if(blockItem2)
|
||||
{
|
||||
return SignalAspect::Proceed;
|
||||
const auto blockState2 = blockItem2->blockState();
|
||||
|
||||
if(blockState2 == BlockState::Free ||
|
||||
(blockState2 == BlockState::Reserved && isPathReserved(*blockItem->block(), ~blockItem->enterSide(), *blockItem2->block())))
|
||||
{
|
||||
return SignalAspect::Proceed;
|
||||
}
|
||||
}
|
||||
else if(signalItem2)
|
||||
{
|
||||
auto signalTile = signalItem2->signal();
|
||||
if(signalTile && signalTile->aspect != SignalAspect::Unknown && signalTile->aspect != SignalAspect::Stop)
|
||||
{
|
||||
switch(signalTile->aspect.value())
|
||||
{
|
||||
case SignalAspect::ProceedReducedSpeed:
|
||||
case SignalAspect::Proceed:
|
||||
return SignalAspect::Proceed;
|
||||
|
||||
case SignalAspect::Stop:
|
||||
case SignalAspect::Unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SignalAspect::ProceedReducedSpeed;
|
||||
}
|
||||
if(states[0] == BlockState::Reserved)
|
||||
{
|
||||
const auto path = signal().reservedPath();
|
||||
if(path && path->toBlock() == getBlock(0))
|
||||
{
|
||||
//! \todo check next block reserved and signal state
|
||||
|
||||
return SignalAspect::ProceedReducedSpeed;
|
||||
}
|
||||
}
|
||||
return SignalAspect::Stop;
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,11 @@ bool SignalRailTile::doSetAspect(SignalAspect value)
|
||||
if(!values->contains(static_cast<int64_t>(value)))
|
||||
return false;
|
||||
(*outputMap)[value]->execute();
|
||||
aspect.setValueInternal(value);
|
||||
if(aspect != value)
|
||||
{
|
||||
aspect.setValueInternal(value);
|
||||
aspectChanged(*this, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -54,6 +54,8 @@ class SignalRailTile : public StraightRailTile
|
||||
void evaluate();
|
||||
|
||||
public:
|
||||
boost::signals2::signal<void (const SignalRailTile&, SignalAspect)> aspectChanged;
|
||||
|
||||
Property<std::string> name;
|
||||
Property<AutoYesNo> requireReservation;
|
||||
Property<SignalAspect> aspect;
|
||||
|
||||
@ -31,4 +31,9 @@ enum class BlockSide : uint8_t
|
||||
B = 1,
|
||||
};
|
||||
|
||||
constexpr BlockSide operator ~(const BlockSide value)
|
||||
{
|
||||
return (value == BlockSide::B) ? BlockSide::A : BlockSide::B;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren