board: made signals aware of path reservation #WIP
Dieser Commit ist enthalten in:
Ursprung
cf18271bc8
Commit
8f636f2be4
@ -23,6 +23,7 @@
|
||||
#include "enum.hpp"
|
||||
#include "../network/abstractproperty.hpp"
|
||||
#include <traintastic/locale/locale.hpp>
|
||||
#include <traintastic/enum/autoyesno.hpp>
|
||||
#include <traintastic/enum/color.hpp>
|
||||
#include <traintastic/enum/decoderfunctionfunction.hpp>
|
||||
#include <traintastic/enum/decoderfunctiontype.hpp>
|
||||
@ -85,6 +86,7 @@ QVector<qint64> enumValues(const QString& enumName)
|
||||
|
||||
QString translateEnum(const QString& enumName, qint64 value)
|
||||
{
|
||||
TRANSLATE_ENUM(AutoYesNo)
|
||||
TRANSLATE_ENUM(Color)
|
||||
TRANSLATE_ENUM(DecoderFunctionFunction)
|
||||
TRANSLATE_ENUM(DecoderFunctionType)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* server/src/board/map/signalpath.cpp
|
||||
* server/src/board/map/abstractsignalpath.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
@ -20,45 +20,108 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "signalpath.hpp"
|
||||
#include "abstractsignalpath.hpp"
|
||||
#include "../../core/objectproperty.tpp"
|
||||
#include "../tile/rail/blockrailtile.hpp"
|
||||
#include "../tile/rail/turnout/turnoutrailtile.hpp"
|
||||
#include "../tile/rail/directioncontrolrailtile.hpp"
|
||||
#include "../tile/rail/onewayrailtile.hpp"
|
||||
#include "../tile/rail/linkrailtile.hpp"
|
||||
#include "../map/signalpath.hpp"
|
||||
#include "../tile/rail/signal/signalrailtile.hpp"
|
||||
#include "../map/abstractsignalpath.hpp"
|
||||
#include "../../train/train.hpp" // FIXME: required due to forward declaration
|
||||
|
||||
SignalPath::SignalPath(const Node& signalNode, size_t blocksAhead, std::function<void(const std::vector<BlockState>&)> onEvaluated)
|
||||
: m_signalNode{signalNode}
|
||||
, m_onEvaluated{std::move(onEvaluated)}
|
||||
AbstractSignalPath::AbstractSignalPath(SignalRailTile& signal)
|
||||
: m_signal{signal}
|
||||
{
|
||||
if(auto link = signalNode.getLink(1))
|
||||
m_root = findBlocks(signalNode, *link, blocksAhead);
|
||||
evaluate();
|
||||
}
|
||||
|
||||
SignalPath::~SignalPath()
|
||||
AbstractSignalPath::AbstractSignalPath(SignalRailTile& signal, size_t blocksAhead)//, std::function<void(const std::vector<BlockState>&)> onEvaluated)
|
||||
: AbstractSignalPath(signal)
|
||||
{
|
||||
const auto& signalNode = signal.node()->get();
|
||||
if(auto link = signalNode.getLink(1); link && blocksAhead != 0)
|
||||
m_root = findBlocks(signalNode, *link, blocksAhead);
|
||||
|
||||
{
|
||||
// Require a reserved path if there is at least one turnout in the path to the next block.
|
||||
// NOTE: this can be overriden using the signal's requireReservation property.
|
||||
const AbstractSignalPath::Item* item = m_root.get();
|
||||
while(item)
|
||||
{
|
||||
if(dynamic_cast<const BlockItem*>(item))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(dynamic_cast<const TurnoutItem*>(item))
|
||||
{
|
||||
m_requireReservation = true;
|
||||
break;
|
||||
}
|
||||
item = item->next().get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractSignalPath::~AbstractSignalPath()
|
||||
{
|
||||
for(auto& connection : m_connections)
|
||||
{
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void SignalPath::evaluate()
|
||||
void AbstractSignalPath::evaluate()
|
||||
{
|
||||
const bool stop = !signal().hasReservedPath() && requireReservation();
|
||||
|
||||
setAspect(stop ? SignalAspect::Stop : determineAspect());
|
||||
}
|
||||
|
||||
bool AbstractSignalPath::requireReservation() const
|
||||
{
|
||||
return (m_signal.requireReservation == AutoYesNo::Yes || (m_signal.requireReservation == AutoYesNo::Auto && m_requireReservation));
|
||||
}
|
||||
|
||||
void AbstractSignalPath::getBlockStates(tcb::span<BlockState> blockStates) const
|
||||
{
|
||||
size_t i = 0;
|
||||
const Item* item = m_root.get();
|
||||
while(item && i < blockStates.size())
|
||||
{
|
||||
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
|
||||
{
|
||||
blockStates[i] = blockItem->blockState();
|
||||
i++;
|
||||
}
|
||||
item = item->next().get();
|
||||
}
|
||||
|
||||
if(i < blockStates.size())
|
||||
{
|
||||
std::fill(blockStates.data() + i, blockStates.data() + blockStates.size(), BlockState::Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockRailTile> AbstractSignalPath::getBlock(size_t index) const
|
||||
{
|
||||
std::vector<BlockState> blockStates;
|
||||
const Item* item = m_root.get();
|
||||
while(item)
|
||||
{
|
||||
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
|
||||
blockStates.emplace_back(blockItem->blockState());
|
||||
{
|
||||
if(index == 0)
|
||||
{
|
||||
return blockItem->block();
|
||||
}
|
||||
index--;
|
||||
}
|
||||
item = item->next().get();
|
||||
}
|
||||
m_onEvaluated(blockStates);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node, const Link& link, size_t blocksAhead)
|
||||
std::unique_ptr<const AbstractSignalPath::Item> AbstractSignalPath::findBlocks(const Node& node, const Link& link, size_t blocksAhead)
|
||||
{
|
||||
const auto& nextNode = link.getNext(node);
|
||||
auto tile = nextNode.tile().shared_ptr<Tile>();
|
||||
@ -75,7 +138,7 @@ std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node,
|
||||
if(blocksAhead > 1)
|
||||
if(const auto& nextLink = otherLink(nextNode, link))
|
||||
next = findBlocks(nextNode, *nextLink, blocksAhead - 1);
|
||||
return std::unique_ptr<const SignalPath::Item>{new BlockItem(block, std::move(next))};
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{new BlockItem(block, std::move(next))};
|
||||
}
|
||||
if(auto turnout = std::dynamic_pointer_cast<TurnoutRailTile>(tile))
|
||||
{
|
||||
@ -92,7 +155,7 @@ std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node,
|
||||
}
|
||||
|
||||
if(!next.empty())
|
||||
return std::unique_ptr<const SignalPath::Item>{new TurnoutItem(turnout, std::move(next))};
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{new TurnoutItem(turnout, std::move(next))};
|
||||
}
|
||||
else if(auto direction = std::dynamic_pointer_cast<DirectionControlRailTile>(tile))
|
||||
{
|
||||
@ -109,7 +172,7 @@ std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node,
|
||||
evaluate();
|
||||
}));
|
||||
|
||||
return std::unique_ptr<const SignalPath::Item>{
|
||||
return std::unique_ptr<const AbstractSignalPath::Item>{
|
||||
new DirectionControlItem(
|
||||
direction,
|
||||
nextNode.getLink(0).get() == &link ? DirectionControlState::AtoB : DirectionControlState::BtoA,
|
||||
@ -150,7 +213,7 @@ std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node,
|
||||
{
|
||||
if(const auto& nextLink = otherLink(nextNode, link))
|
||||
{
|
||||
if(&nextNode == &m_signalNode)
|
||||
if(&nextNode == &m_signal.node()->get())
|
||||
return {}; // we're reached oursels
|
||||
|
||||
return findBlocks(nextNode, *nextLink, blocksAhead);
|
||||
@ -161,15 +224,27 @@ std::unique_ptr<const SignalPath::Item> SignalPath::findBlocks(const Node& node,
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
BlockState SignalPath::BlockItem::blockState() const
|
||||
void AbstractSignalPath::setAspect(SignalAspect value) const
|
||||
{
|
||||
if(auto block = m_block.lock())
|
||||
return block->state;
|
||||
m_signal.setAspect(value);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<BlockRailTile> AbstractSignalPath::BlockItem::block() const noexcept
|
||||
{
|
||||
return m_block.lock();
|
||||
}
|
||||
|
||||
BlockState AbstractSignalPath::BlockItem::blockState() const
|
||||
{
|
||||
if(auto blk = block())
|
||||
{
|
||||
return blk->state;
|
||||
}
|
||||
return BlockState::Unknown;
|
||||
}
|
||||
|
||||
const std::unique_ptr<const SignalPath::Item>& SignalPath::DirectionControlItem::next() const
|
||||
const std::unique_ptr<const AbstractSignalPath::Item>& AbstractSignalPath::DirectionControlItem::next() const
|
||||
{
|
||||
if(auto directionControl = m_directionControl.lock())
|
||||
{
|
||||
@ -180,7 +255,7 @@ const std::unique_ptr<const SignalPath::Item>& SignalPath::DirectionControlItem:
|
||||
return noItem;
|
||||
}
|
||||
|
||||
const std::unique_ptr<const SignalPath::Item>& SignalPath::TurnoutItem::next() const
|
||||
const std::unique_ptr<const AbstractSignalPath::Item>& AbstractSignalPath::TurnoutItem::next() const
|
||||
{
|
||||
if(auto turnout = m_turnout.lock())
|
||||
if(auto it = m_next.find(turnout->position.value()); it != m_next.end())
|
||||
@ -34,9 +34,19 @@ class TurnoutRailTile;
|
||||
enum class TurnoutPosition : uint8_t;
|
||||
class DirectionControlRailTile;
|
||||
enum class DirectionControlState : uint8_t;
|
||||
class SignalRailTile;
|
||||
enum class SignalAspect : uint8_t;
|
||||
|
||||
class SignalPath : public Path
|
||||
class AbstractSignalPath : public Path
|
||||
{
|
||||
private:
|
||||
SignalRailTile& m_signal;
|
||||
|
||||
AbstractSignalPath(const AbstractSignalPath&) = delete;
|
||||
AbstractSignalPath& operator =(const AbstractSignalPath&) = delete;
|
||||
|
||||
void setAspect(SignalAspect value) const;
|
||||
|
||||
private:
|
||||
class Item
|
||||
{
|
||||
@ -73,6 +83,7 @@ class SignalPath : public Path
|
||||
return m_next;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockRailTile> block() const noexcept;
|
||||
BlockState blockState() const;
|
||||
};
|
||||
|
||||
@ -110,15 +121,10 @@ class SignalPath : public Path
|
||||
const std::unique_ptr<const Item>& next() const final;
|
||||
};
|
||||
|
||||
const Node& m_signalNode;
|
||||
std::unique_ptr<const Item> m_root;
|
||||
bool m_requireReservation = false;
|
||||
std::vector<boost::signals2::connection> m_connections;
|
||||
std::function<void(const std::vector<BlockState>&)> m_onEvaluated;
|
||||
|
||||
SignalPath(const SignalPath&) = delete;
|
||||
SignalPath& operator =(const SignalPath&) = delete;
|
||||
|
||||
void evaluate();
|
||||
std::unique_ptr<const Item> findBlocks(const Node& node, const Link& link, size_t blocksAhead);
|
||||
|
||||
inline std::unique_ptr<const Item> findBlocks(const Node& node, const std::shared_ptr<const Link>& link, size_t blocksAhead)
|
||||
@ -128,9 +134,25 @@ class SignalPath : public Path
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
inline const SignalRailTile& signal() const
|
||||
{
|
||||
return m_signal;
|
||||
}
|
||||
|
||||
bool requireReservation() const;
|
||||
|
||||
virtual SignalAspect determineAspect() const = 0;
|
||||
|
||||
void getBlockStates(tcb::span<BlockState> blockStates) const;
|
||||
std::shared_ptr<BlockRailTile> getBlock(size_t index) const;
|
||||
|
||||
public:
|
||||
SignalPath(const Node& signalNode, size_t blocksAhead, std::function<void(const std::vector<BlockState>&)> onEvaluated);
|
||||
~SignalPath();
|
||||
AbstractSignalPath(SignalRailTile& signal);
|
||||
AbstractSignalPath(SignalRailTile& signal, size_t blocksAhead);
|
||||
~AbstractSignalPath();
|
||||
|
||||
void evaluate();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -401,7 +401,7 @@ bool BlockPath::reserve(const std::shared_ptr<Train>& train, bool dryRun)
|
||||
{
|
||||
if(auto signal = signalWeak.lock())
|
||||
{
|
||||
if(!signal->reserve(SignalRailTile::Pass{}, dryRun))
|
||||
if(!signal->reserve(shared_from_this(), dryRun))
|
||||
{
|
||||
assert(dryRun);
|
||||
return false;
|
||||
|
||||
@ -48,7 +48,7 @@ class Train;
|
||||
/**
|
||||
* \brief A path between two blocks
|
||||
*/
|
||||
class BlockPath : public Path
|
||||
class BlockPath : public Path, public std::enable_shared_from_this<BlockPath>
|
||||
{
|
||||
private:
|
||||
BlockRailTile& m_fromBlock;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2020-2022 Reinder Feenstra
|
||||
* Copyright (C) 2020-2023 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "signal2aspectrailtile.hpp"
|
||||
#include "../../../map/signalpath.hpp"
|
||||
#include "../../../map/abstractsignalpath.hpp"
|
||||
#include "../../../map/blockpath.hpp"
|
||||
#include "../../../../core/attributes.hpp"
|
||||
#include "../../../../core/method.tpp"
|
||||
#include "../../../../core/objectproperty.tpp"
|
||||
@ -29,6 +30,39 @@
|
||||
static const std::array<SignalAspect, 3> aspectValues = {SignalAspect::Stop, SignalAspect::Proceed, SignalAspect::Unknown};
|
||||
static const std::array<SignalAspect, 2> setAspectValues = {SignalAspect::Stop, SignalAspect::Proceed};
|
||||
|
||||
namespace
|
||||
{
|
||||
class SignalPath : public AbstractSignalPath
|
||||
{
|
||||
protected:
|
||||
SignalAspect determineAspect() const final
|
||||
{
|
||||
std::array<BlockState, 1> states;
|
||||
getBlockStates(states);
|
||||
|
||||
if(!requireReservation() && states[0] == BlockState::Free)
|
||||
{
|
||||
return SignalAspect::Proceed;
|
||||
}
|
||||
if(states[0] == BlockState::Reserved)
|
||||
{
|
||||
const auto path = signal().reservedPath();
|
||||
if(path && path->toBlock() == getBlock(0))
|
||||
{
|
||||
return SignalAspect::Proceed;
|
||||
}
|
||||
}
|
||||
return SignalAspect::Stop;
|
||||
}
|
||||
|
||||
public:
|
||||
SignalPath(Signal2AspectRailTile& signal)
|
||||
: AbstractSignalPath(signal, 1)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Signal2AspectRailTile::Signal2AspectRailTile(World& world, std::string_view _id) :
|
||||
SignalRailTile(world, _id, TileId::RailSignal2Aspect)
|
||||
{
|
||||
@ -43,9 +77,6 @@ Signal2AspectRailTile::Signal2AspectRailTile(World& world, std::string_view _id)
|
||||
|
||||
void Signal2AspectRailTile::boardModified()
|
||||
{
|
||||
m_signalPath = std::make_unique<SignalPath>(m_node, 1,
|
||||
[this](const std::vector<BlockState>& states)
|
||||
{
|
||||
setAspect(!states.empty() && states[0] == BlockState::Free ? SignalAspect::Proceed : SignalAspect::Stop);
|
||||
});
|
||||
m_signalPath = std::make_unique<SignalPath>(*this);
|
||||
SignalRailTile::boardModified();
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2020-2022 Reinder Feenstra
|
||||
* Copyright (C) 2020-2023 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "signal3aspectrailtile.hpp"
|
||||
#include "../../../map/signalpath.hpp"
|
||||
#include "../../../map/abstractsignalpath.hpp"
|
||||
#include "../../../map/blockpath.hpp"
|
||||
#include "../../../../core/attributes.hpp"
|
||||
#include "../../../../core/method.tpp"
|
||||
#include "../../../../core/objectproperty.tpp"
|
||||
@ -29,6 +30,45 @@
|
||||
static const std::array<SignalAspect, 4> aspectValues = {SignalAspect::Stop, SignalAspect::ProceedReducedSpeed, SignalAspect::Proceed, SignalAspect::Unknown};
|
||||
static const std::array<SignalAspect, 3> setAspectValues = {SignalAspect::Stop, SignalAspect::ProceedReducedSpeed, SignalAspect::Proceed};
|
||||
|
||||
namespace
|
||||
{
|
||||
class SignalPath : public AbstractSignalPath
|
||||
{
|
||||
protected:
|
||||
SignalAspect determineAspect() const final
|
||||
{
|
||||
std::array<BlockState, 2> states;
|
||||
getBlockStates(states);
|
||||
|
||||
if(!requireReservation() && states[0] == BlockState::Free)
|
||||
{
|
||||
if(states[1] == BlockState::Free)
|
||||
{
|
||||
return SignalAspect::Proceed;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public:
|
||||
SignalPath(Signal3AspectRailTile& signal)
|
||||
: AbstractSignalPath(signal, 2)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Signal3AspectRailTile::Signal3AspectRailTile(World& world, std::string_view _id) :
|
||||
SignalRailTile(world, _id, TileId::RailSignal3Aspect)
|
||||
{
|
||||
@ -43,17 +83,6 @@ Signal3AspectRailTile::Signal3AspectRailTile(World& world, std::string_view _id)
|
||||
|
||||
void Signal3AspectRailTile::boardModified()
|
||||
{
|
||||
m_signalPath = std::make_unique<SignalPath>(m_node, 2,
|
||||
[this](const std::vector<BlockState>& states)
|
||||
{
|
||||
if(!states.empty() && states[0] == BlockState::Free)
|
||||
{
|
||||
if(states.size() >= 2 && states[1] == BlockState::Free)
|
||||
setAspect(SignalAspect::Proceed);
|
||||
else
|
||||
setAspect(SignalAspect::ProceedReducedSpeed);
|
||||
}
|
||||
else
|
||||
setAspect(SignalAspect::Stop);
|
||||
});
|
||||
m_signalPath = std::make_unique<SignalPath>(*this);
|
||||
SignalRailTile::boardModified();
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "signalrailtile.hpp"
|
||||
#include "../../../map/signalpath.hpp"
|
||||
#include "../../../map/abstractsignalpath.hpp"
|
||||
#include "../../../../core/attributes.hpp"
|
||||
#include "../../../../core/method.tpp"
|
||||
#include "../../../../core/objectproperty.tpp"
|
||||
@ -32,6 +32,7 @@ SignalRailTile::SignalRailTile(World& world, std::string_view _id, TileId tileId
|
||||
StraightRailTile(world, _id, tileId),
|
||||
m_node{*this, 2},
|
||||
name{this, "name", std::string(_id), PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::ScriptReadOnly},
|
||||
requireReservation{this, "require_reservation", AutoYesNo::Auto, PropertyFlags::ReadWrite | PropertyFlags::Store},
|
||||
aspect{this, "aspect", SignalAspect::Unknown, PropertyFlags::ReadOnly | PropertyFlags::StoreState | PropertyFlags::ScriptReadOnly},
|
||||
outputMap{this, "output_map", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject | PropertyFlags::NoScript},
|
||||
setAspect{*this, "set_aspect", MethodFlags::ScriptCallable, [this](SignalAspect value) { return doSetAspect(value); }}
|
||||
@ -42,6 +43,10 @@ SignalRailTile::SignalRailTile(World& world, std::string_view _id, TileId tileId
|
||||
Attributes::addEnabled(name, editable);
|
||||
m_interfaceItems.add(name);
|
||||
|
||||
Attributes::addEnabled(requireReservation, editable);
|
||||
Attributes::addValues(requireReservation, autoYesNoValues);
|
||||
m_interfaceItems.add(requireReservation);
|
||||
|
||||
Attributes::addObjectEditor(aspect, false);
|
||||
// aspect is added by sub class
|
||||
|
||||
@ -54,13 +59,25 @@ SignalRailTile::SignalRailTile(World& world, std::string_view _id, TileId tileId
|
||||
|
||||
SignalRailTile::~SignalRailTile() = default; // default here, so we can use a forward declaration of SignalPath in the header.
|
||||
|
||||
bool SignalRailTile::reserve(Pass, bool dryRun)
|
||||
bool SignalRailTile::hasReservedPath() const noexcept
|
||||
{
|
||||
return !m_blockPath.expired();
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockPath> SignalRailTile::reservedPath() const noexcept
|
||||
{
|
||||
return m_blockPath.lock();
|
||||
}
|
||||
|
||||
bool SignalRailTile::reserve(const std::shared_ptr<BlockPath>& blockPath, bool dryRun)
|
||||
{
|
||||
// no conditions yet...
|
||||
|
||||
if(!dryRun)
|
||||
{
|
||||
m_blockPath = blockPath;
|
||||
RailTile::reserve();
|
||||
evaluate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -70,8 +87,24 @@ void SignalRailTile::worldEvent(WorldState state, WorldEvent event)
|
||||
StraightRailTile::worldEvent(state, event);
|
||||
|
||||
const bool editable = contains(state, WorldState::Edit);
|
||||
const bool editableAndStopped = editable && !contains(state, WorldState::Run);
|
||||
|
||||
Attributes::setEnabled(name, editable);
|
||||
Attributes::setEnabled(requireReservation, editableAndStopped);
|
||||
|
||||
if(event == WorldEvent::Run)
|
||||
{
|
||||
evaluate();
|
||||
}
|
||||
}
|
||||
|
||||
void SignalRailTile::boardModified()
|
||||
{
|
||||
if(m_signalPath)
|
||||
{
|
||||
m_signalPath->evaluate();
|
||||
}
|
||||
StraightRailTile::boardModified();
|
||||
}
|
||||
|
||||
bool SignalRailTile::doSetAspect(SignalAspect value)
|
||||
@ -84,3 +117,15 @@ bool SignalRailTile::doSetAspect(SignalAspect value)
|
||||
aspect.setValueInternal(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SignalRailTile::evaluate()
|
||||
{
|
||||
if(m_signalPath) /*[[likely]]*/
|
||||
{
|
||||
m_signalPath->evaluate();
|
||||
}
|
||||
else
|
||||
{
|
||||
setAspect(SignalAspect::Stop);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,13 +24,15 @@
|
||||
#define TRAINTASTIC_SERVER_BOARD_TILE_RAIL_SIGNAL_SIGNALRAILTILE_HPP
|
||||
|
||||
#include "../straightrailtile.hpp"
|
||||
#include <traintastic/enum/autoyesno.hpp>
|
||||
#include "../../../map/node.hpp"
|
||||
#include "../../../../core/method.hpp"
|
||||
#include "../../../../enum/signalaspect.hpp"
|
||||
#include "../../../../core/objectproperty.hpp"
|
||||
#include "../../../../hardware/output/map/signaloutputmap.hpp"
|
||||
|
||||
class SignalPath;
|
||||
class AbstractSignalPath;
|
||||
class BlockPath;
|
||||
|
||||
class SignalRailTile : public StraightRailTile
|
||||
{
|
||||
@ -38,20 +40,22 @@ class SignalRailTile : public StraightRailTile
|
||||
|
||||
protected:
|
||||
Node m_node;
|
||||
std::unique_ptr<SignalPath> m_signalPath;
|
||||
std::unique_ptr<AbstractSignalPath> m_signalPath;
|
||||
std::weak_ptr<BlockPath> m_blockPath;
|
||||
|
||||
SignalRailTile(World& world, std::string_view _id, TileId tileId);
|
||||
|
||||
void worldEvent(WorldState state, WorldEvent event) override;
|
||||
|
||||
void boardModified() override;
|
||||
|
||||
virtual bool doSetAspect(SignalAspect value);
|
||||
|
||||
public:
|
||||
struct Pass
|
||||
{
|
||||
};
|
||||
void evaluate();
|
||||
|
||||
public:
|
||||
Property<std::string> name;
|
||||
Property<AutoYesNo> requireReservation;
|
||||
Property<SignalAspect> aspect;
|
||||
ObjectProperty<SignalOutputMap> outputMap;
|
||||
Method<bool(SignalAspect)> setAspect;
|
||||
@ -61,7 +65,10 @@ class SignalRailTile : public StraightRailTile
|
||||
std::optional<std::reference_wrapper<const Node>> node() const final { return m_node; }
|
||||
std::optional<std::reference_wrapper<Node>> node() final { return m_node; }
|
||||
|
||||
bool reserve(Pass, bool dryRun = false);
|
||||
bool hasReservedPath() const noexcept;
|
||||
std::shared_ptr<BlockPath> reservedPath() const noexcept;
|
||||
|
||||
bool reserve(const std::shared_ptr<BlockPath>& blockPath, bool dryRun = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
51
shared/src/traintastic/enum/autoyesno.hpp
Normale Datei
51
shared/src/traintastic/enum/autoyesno.hpp
Normale Datei
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* shared/src/traintastic/enum/autoyesno.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef TRAINTASTIC_SHARED_TRAINTASTIC_ENUM_AUTOYESNO_HPP
|
||||
#define TRAINTASTIC_SHARED_TRAINTASTIC_ENUM_AUTOYESNO_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include "enum.hpp"
|
||||
|
||||
enum class AutoYesNo : uint8_t
|
||||
{
|
||||
Auto = 0,
|
||||
Yes = 1,
|
||||
No = 2,
|
||||
};
|
||||
|
||||
TRAINTASTIC_ENUM(AutoYesNo, "auto_yes_no", 3,
|
||||
{
|
||||
{AutoYesNo::Auto, "auto"},
|
||||
{AutoYesNo::Yes, "yes"},
|
||||
{AutoYesNo::No, "no"},
|
||||
});
|
||||
|
||||
constexpr std::array<AutoYesNo, 3> autoYesNoValues
|
||||
{
|
||||
AutoYesNo::Auto,
|
||||
AutoYesNo::Yes,
|
||||
AutoYesNo::No,
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -4358,5 +4358,21 @@
|
||||
{
|
||||
"term": "message:W3002",
|
||||
"definition": "NX button not connected to any block"
|
||||
},
|
||||
{
|
||||
"term": "auto_yes_no:auto",
|
||||
"definition": "Auto detect"
|
||||
},
|
||||
{
|
||||
"term": "auto_yes_no:yes",
|
||||
"definition": "Yes"
|
||||
},
|
||||
{
|
||||
"term": "auto_yes_no:no",
|
||||
"definition": "No"
|
||||
},
|
||||
{
|
||||
"term": "board_tile.rail.signal_3_aspect:require_reservation",
|
||||
"definition": "Require reservation"
|
||||
}
|
||||
]
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren