board: added basic identification/RailCom support for blocks
Dieser Commit ist enthalten in:
Ursprung
01e168b57b
Commit
b5b3da9107
@ -1020,13 +1020,23 @@ void TilePainter::drawRailBlock(const QRectF& r, TileRotate rotate, const Object
|
||||
{
|
||||
if(auto* trainBlockStatus = dynamic_cast<TrainBlockStatus*>(block->trains()[0].get())) /*[[likely]]*/
|
||||
{
|
||||
if(const auto& train = trainBlockStatus->train()) /*[[likely]]*/
|
||||
if(const auto& train = trainBlockStatus->train())
|
||||
{
|
||||
if(trainBlockStatus->direction() == BlockTrainDirection::TowardsA)
|
||||
label += "< ";
|
||||
|
||||
label += train->getPropertyValueString("name");
|
||||
|
||||
if(trainBlockStatus->direction() == BlockTrainDirection::TowardsB)
|
||||
label += " >";
|
||||
}
|
||||
else if(auto identification = trainBlockStatus->identification(); !identification.isEmpty())
|
||||
{
|
||||
if(trainBlockStatus->direction() == BlockTrainDirection::TowardsA)
|
||||
label += "< ";
|
||||
|
||||
label += identification;
|
||||
|
||||
if(trainBlockStatus->direction() == BlockTrainDirection::TowardsB)
|
||||
label += " >";
|
||||
}
|
||||
|
||||
@ -45,6 +45,14 @@ BlockTrainDirection TrainBlockStatus::direction() const
|
||||
return static_cast<BlockTrainDirection>(0);
|
||||
}
|
||||
|
||||
QString TrainBlockStatus::identification() const
|
||||
{
|
||||
if(m_identificationProperty) /*[[likely]]*/
|
||||
return m_identificationProperty->toString();
|
||||
assert(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
void TrainBlockStatus::created()
|
||||
{
|
||||
Object::created();
|
||||
@ -57,6 +65,14 @@ void TrainBlockStatus::created()
|
||||
emit changed();
|
||||
});
|
||||
|
||||
m_identificationProperty = dynamic_cast<Property*>(getProperty("identification"));
|
||||
if(m_identificationProperty)
|
||||
connect(m_identificationProperty, &Property::valueChanged, this,
|
||||
[this]()
|
||||
{
|
||||
emit changed();
|
||||
});
|
||||
|
||||
if((m_trainProperty = dynamic_cast<ObjectProperty*>(getProperty("train")))) /*[[likely]]*/
|
||||
{
|
||||
connect(m_trainProperty, &ObjectProperty::valueChanged, this, &TrainBlockStatus::updateTrain);
|
||||
|
||||
@ -39,6 +39,7 @@ class TrainBlockStatus final : public Object
|
||||
private:
|
||||
int m_requestId;
|
||||
Property* m_directionProperty = nullptr;
|
||||
Property* m_identificationProperty = nullptr;
|
||||
ObjectProperty* m_trainProperty = nullptr;
|
||||
ObjectPtr m_train;
|
||||
|
||||
@ -52,6 +53,7 @@ class TrainBlockStatus final : public Object
|
||||
~TrainBlockStatus() final;
|
||||
|
||||
BlockTrainDirection direction() const;
|
||||
QString identification() const;
|
||||
|
||||
const ObjectPtr& train() const
|
||||
{
|
||||
|
||||
@ -120,8 +120,7 @@ BlockRailTile::BlockRailTile(World& world, std::string_view _id) :
|
||||
if(it == trains.end()) /*[[unlikely]]*/
|
||||
return; // can't remove a train that isn't in the block
|
||||
|
||||
oldTrain->blocks.removeInternal(*it);
|
||||
trains.removeInternal(*it);
|
||||
(**it).destroy();
|
||||
|
||||
updateTrainMethodEnabled();
|
||||
if(state == BlockState::Reserved)
|
||||
@ -217,6 +216,58 @@ void BlockRailTile::inputItemValueChanged(BlockInputMapItem& item)
|
||||
updateState();
|
||||
}
|
||||
|
||||
void BlockRailTile::identificationEvent(BlockInputMapItem& item, IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t category)
|
||||
{
|
||||
const auto self = shared_ptr<BlockRailTile>();
|
||||
BlockTrainDirection blockDirection = BlockTrainDirection::Unknown;
|
||||
if(direction != Direction::Unknown)
|
||||
blockDirection = (direction == Direction::Reverse) ? BlockTrainDirection::TowardsB : BlockTrainDirection::TowardsA;
|
||||
|
||||
if(trains.empty())
|
||||
{
|
||||
switch(eventType)
|
||||
{
|
||||
case IdentificationEventType::Absent:
|
||||
break; // nothing to do...its gone
|
||||
|
||||
case IdentificationEventType::Present:
|
||||
//!< \todo assign train (if allowed and possible)
|
||||
trains.appendInternal(TrainBlockStatus::create(*this, std::string("#").append(std::to_string(identifier)), blockDirection));
|
||||
if(state == BlockState::Free || state == BlockState::Unknown)
|
||||
updateState();
|
||||
break;
|
||||
|
||||
case IdentificationEventType::Seen:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(eventType)
|
||||
{
|
||||
case IdentificationEventType::Absent:
|
||||
{
|
||||
const auto identification = std::string("#").append(std::to_string(identifier));
|
||||
for(auto& train : trains)
|
||||
{
|
||||
if(train->identification.value() == identification)
|
||||
{
|
||||
train->destroy();
|
||||
updateState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IdentificationEventType::Present:
|
||||
break;
|
||||
|
||||
case IdentificationEventType::Seen:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlockRailTile::updateState()
|
||||
{
|
||||
if(!inputMap->items.empty())
|
||||
|
||||
@ -77,6 +77,7 @@ class BlockRailTile : public RailTile
|
||||
void getConnectors(std::vector<Connector>& connectors) const final;
|
||||
|
||||
void inputItemValueChanged(BlockInputMapItem& item);
|
||||
void identificationEvent(BlockInputMapItem& item, IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t category);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -28,6 +28,11 @@ void StateObject::addToWorld(World& world, StateObject& object)
|
||||
world.m_objects.emplace(object.getObjectId(), object.weak_from_this());
|
||||
}
|
||||
|
||||
void StateObject::removeFromWorld(World& world, StateObject& object)
|
||||
{
|
||||
world.m_objects.erase(object.m_id);
|
||||
}
|
||||
|
||||
StateObject::StateObject(std::string id)
|
||||
: m_id{std::move(id)}
|
||||
{
|
||||
|
||||
@ -37,6 +37,8 @@ private:
|
||||
std::string m_id;
|
||||
|
||||
protected:
|
||||
static void removeFromWorld(World& world, StateObject& object);
|
||||
|
||||
void save(WorldSaver& saver, nlohmann::json& data, nlohmann::json& state) const override;
|
||||
|
||||
public:
|
||||
|
||||
@ -58,6 +58,18 @@ BlockInputMapItem::BlockInputMapItem(BlockInputMap& parent, uint32_t itemId) :
|
||||
if(input)
|
||||
inputPropertyChanged(input->value);
|
||||
}}
|
||||
, identification{this, "identification", nullptr, PropertyFlags::ReadWrite | PropertyFlags::Store,
|
||||
nullptr,
|
||||
[this](const std::shared_ptr<Identification>& value)
|
||||
{
|
||||
if(identification)
|
||||
disconnectIdentification(*identification);
|
||||
|
||||
if(value)
|
||||
connectIdentification(*value);
|
||||
|
||||
return true;
|
||||
}}
|
||||
{
|
||||
auto& world = getWorld(m_parent);
|
||||
const bool editable = contains(world.state.value(), WorldState::Edit);
|
||||
@ -74,6 +86,9 @@ BlockInputMapItem::BlockInputMapItem(BlockInputMap& parent, uint32_t itemId) :
|
||||
m_interfaceItems.add(type);
|
||||
Attributes::addEnabled(invert, editable && stopped);
|
||||
m_interfaceItems.add(invert);
|
||||
Attributes::addEnabled(identification, editable && stopped);
|
||||
Attributes::addObjectList(identification, world.identifications);
|
||||
m_interfaceItems.add(identification);
|
||||
}
|
||||
|
||||
BlockInputMapItem::~BlockInputMapItem()
|
||||
@ -81,6 +96,8 @@ BlockInputMapItem::~BlockInputMapItem()
|
||||
assert(!input);
|
||||
assert(!m_inputPropertyChanged.connected());
|
||||
assert(!m_inputDestroying.connected());
|
||||
assert(!identification);
|
||||
assert(!m_identificationDestroying.connected());
|
||||
}
|
||||
|
||||
std::string BlockInputMapItem::getObjectId() const
|
||||
@ -100,11 +117,14 @@ void BlockInputMapItem::loaded()
|
||||
|
||||
if(input)
|
||||
connectInput(*input);
|
||||
if(identification)
|
||||
connectIdentification(*identification);
|
||||
}
|
||||
|
||||
void BlockInputMapItem::destroying()
|
||||
{
|
||||
input = nullptr;
|
||||
identification = nullptr;
|
||||
InputMapItem::destroying();
|
||||
}
|
||||
|
||||
@ -119,6 +139,7 @@ void BlockInputMapItem::worldEvent(WorldState state, WorldEvent event)
|
||||
Attributes::setEnabled(input, editable && stopped);
|
||||
Attributes::setEnabled(type, false/*editable && stopped*/);
|
||||
Attributes::setEnabled(invert, editable && stopped);
|
||||
Attributes::setEnabled(identification, editable && stopped);
|
||||
}
|
||||
|
||||
void BlockInputMapItem::connectInput(Input& object)
|
||||
@ -147,6 +168,29 @@ void BlockInputMapItem::inputPropertyChanged(BaseProperty& property)
|
||||
setValue(toSensorState(type, input->value.value() ^ invert.value()));
|
||||
}
|
||||
|
||||
void BlockInputMapItem::connectIdentification(Identification& object)
|
||||
{
|
||||
object.consumers.appendInternal(m_parent.parent().shared_from_this());
|
||||
m_identificationDestroying = object.onDestroying.connect(
|
||||
[this]([[maybe_unused]] Object& obj)
|
||||
{
|
||||
assert(identification.value().get() == &obj);
|
||||
identification = nullptr;
|
||||
});
|
||||
m_identificationEvent = object.onEvent.connect(
|
||||
[this](IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t category)
|
||||
{
|
||||
static_cast<BlockRailTile&>(m_parent.parent()).identificationEvent(*this, eventType, identifier, direction, category);
|
||||
});
|
||||
}
|
||||
|
||||
void BlockInputMapItem::disconnectIdentification(Identification& object)
|
||||
{
|
||||
m_identificationEvent.disconnect();
|
||||
m_identificationDestroying.disconnect();
|
||||
object.consumers.removeInternal(m_parent.parent().shared_from_this());
|
||||
}
|
||||
|
||||
void BlockInputMapItem::setValue(SensorState value)
|
||||
{
|
||||
if(m_value != value)
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "../input.hpp"
|
||||
#include "../../../enum/sensortype.hpp"
|
||||
#include "../../../enum/sensorstate.hpp"
|
||||
#include "../../identification/identification.hpp"
|
||||
|
||||
class BlockInputMap;
|
||||
|
||||
@ -40,11 +41,17 @@ class BlockInputMapItem final : public InputMapItem
|
||||
const uint32_t m_itemId;
|
||||
boost::signals2::connection m_inputDestroying;
|
||||
boost::signals2::connection m_inputPropertyChanged;
|
||||
boost::signals2::connection m_identificationDestroying;
|
||||
boost::signals2::connection m_identificationEvent;
|
||||
SensorState m_value;
|
||||
|
||||
void connectInput(Input& object);
|
||||
void disconnectInput(Input& object);
|
||||
void inputPropertyChanged(BaseProperty& property);
|
||||
|
||||
void connectIdentification(Identification& object);
|
||||
void disconnectIdentification(Identification& object);
|
||||
|
||||
void setValue(SensorState value);
|
||||
|
||||
protected:
|
||||
@ -58,6 +65,7 @@ class BlockInputMapItem final : public InputMapItem
|
||||
ObjectProperty<Input> input;
|
||||
Property<SensorType> type;
|
||||
Property<bool> invert;
|
||||
ObjectProperty<Identification> identification;
|
||||
|
||||
BlockInputMapItem(BlockInputMap& parent, uint32_t itemId);
|
||||
~BlockInputMapItem() final;
|
||||
|
||||
@ -30,21 +30,49 @@
|
||||
std::shared_ptr<TrainBlockStatus> TrainBlockStatus::create(BlockRailTile& block_, Train& train_, BlockTrainDirection direction_, std::string_view id)
|
||||
{
|
||||
World& world = block_.world();
|
||||
auto p = std::make_shared<TrainBlockStatus>(block_, train_, direction_, id.empty() ? world.getUniqueId(TrainBlockStatus::classId) : std::string{id});
|
||||
auto p = std::make_shared<TrainBlockStatus>(id.empty() ? world.getUniqueId(TrainBlockStatus::classId) : std::string{id});
|
||||
p->block.setValueInternal(block_.shared_ptr<BlockRailTile>());
|
||||
p->train.setValueInternal(train_.shared_ptr<Train>());
|
||||
p->direction.setValueInternal(direction_);
|
||||
TrainBlockStatus::addToWorld(world, *p);
|
||||
return p;
|
||||
}
|
||||
|
||||
TrainBlockStatus::TrainBlockStatus(BlockRailTile& block_, Train& train_, BlockTrainDirection direction_, std::string id)
|
||||
std::shared_ptr<TrainBlockStatus> TrainBlockStatus::create(BlockRailTile& block_, std::string identification_, BlockTrainDirection direction_, std::string_view id)
|
||||
{
|
||||
World& world = block_.world();
|
||||
auto p = std::make_shared<TrainBlockStatus>(id.empty() ? world.getUniqueId(TrainBlockStatus::classId) : std::string{id});
|
||||
p->block.setValueInternal(block_.shared_ptr<BlockRailTile>());
|
||||
p->identification.setValueInternal(std::move(identification_));
|
||||
p->direction.setValueInternal(direction_);
|
||||
TrainBlockStatus::addToWorld(world, *p);
|
||||
return p;
|
||||
}
|
||||
|
||||
TrainBlockStatus::TrainBlockStatus(std::string id)
|
||||
: StateObject(std::move(id))
|
||||
, block{this, "block", block_.shared_ptr<BlockRailTile>(), PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, train{this, "train", train_.shared_ptr<Train>(), PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, direction{this, "direction", direction_, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, block{this, "block", nullptr, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, train{this, "train", nullptr, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, identification{this, "identification", "", PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
, direction{this, "direction", BlockTrainDirection::TowardsA, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
{
|
||||
m_interfaceItems.add(block);
|
||||
|
||||
m_interfaceItems.add(train);
|
||||
|
||||
m_interfaceItems.add(identification);
|
||||
|
||||
Attributes::addValues(direction, blockTrainDirectionValues);
|
||||
m_interfaceItems.add(direction);
|
||||
}
|
||||
|
||||
void TrainBlockStatus::destroying()
|
||||
{
|
||||
auto self = shared_ptr<TrainBlockStatus>();
|
||||
if(block)
|
||||
block->trains.removeInternal(self);
|
||||
if(train)
|
||||
train->blocks.removeInternal(self);
|
||||
removeFromWorld(block->world(), *this);
|
||||
StateObject::destroying();
|
||||
}
|
||||
|
||||
@ -36,14 +36,19 @@ class TrainBlockStatus final : public StateObject
|
||||
{
|
||||
CLASS_ID("train_block_status");
|
||||
|
||||
protected:
|
||||
void destroying() final;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<TrainBlockStatus> create(BlockRailTile& block_, Train& train_, BlockTrainDirection direction_, std::string_view id = {});
|
||||
static std::shared_ptr<TrainBlockStatus> create(BlockRailTile& block_, std::string identification_, BlockTrainDirection direction_, std::string_view id = {});
|
||||
|
||||
ObjectProperty<BlockRailTile> block;
|
||||
ObjectProperty<Train> train;
|
||||
Property<std::string> identification;
|
||||
Property<BlockTrainDirection> direction; //!< \brief Train direction from the block perspective
|
||||
|
||||
TrainBlockStatus(BlockRailTile& block_, Train& train_, BlockTrainDirection direction_, std::string id);
|
||||
TrainBlockStatus(std::string id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -29,24 +29,30 @@
|
||||
|
||||
enum class BlockTrainDirection : uint8_t
|
||||
{
|
||||
Unknown = 0,
|
||||
TowardsA = 1, //!< West for horizontal blocks, South for vertical blocks.
|
||||
TowardsB = 2, //!< East for horizontal blocks, North for vertical blocks.
|
||||
};
|
||||
|
||||
TRAINTASTIC_ENUM(BlockTrainDirection, "block_train_direction", 2,
|
||||
TRAINTASTIC_ENUM(BlockTrainDirection, "block_train_direction", 3,
|
||||
{
|
||||
{BlockTrainDirection::Unknown, "unknown"},
|
||||
{BlockTrainDirection::TowardsA, "towards_a"},
|
||||
{BlockTrainDirection::TowardsB, "towards_b"}
|
||||
});
|
||||
|
||||
constexpr std::array<BlockTrainDirection, 2> blockTrainDirectionValues
|
||||
constexpr std::array<BlockTrainDirection, 3> blockTrainDirectionValues
|
||||
{
|
||||
BlockTrainDirection::Unknown,
|
||||
BlockTrainDirection::TowardsA,
|
||||
BlockTrainDirection::TowardsB,
|
||||
};
|
||||
|
||||
constexpr BlockTrainDirection operator !(BlockTrainDirection value)
|
||||
{
|
||||
if(value == BlockTrainDirection::Unknown)
|
||||
return BlockTrainDirection::Unknown;
|
||||
|
||||
return (value == BlockTrainDirection::TowardsA) ? BlockTrainDirection::TowardsB : BlockTrainDirection::TowardsA;
|
||||
}
|
||||
|
||||
|
||||
@ -4318,5 +4318,9 @@
|
||||
{
|
||||
"term": "message:E3001",
|
||||
"definition": "Can't delete rail vehicle when in active train"
|
||||
},
|
||||
{
|
||||
"term": "input_map_item.block:identification",
|
||||
"definition": "Identification"
|
||||
}
|
||||
]
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren