17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 06:19:19 +02:00

feat(scenery): models laid along curves (sweep nodes), bent to follow the paths or repeated along them, loaded and saved with the scenery; trainsets put on a path while the simulation runs; trainset turned around by reversed after its header: the first vehicle stays at the offset and leads towards point 1, the rest stands behind it; launcher keeps reversed trainsets and can turn one around; memory cells saved with the new name of the path they name; events tell their targets and the events of a multiple event; renderer tells whether the cursor is over a surface; vehicle placed in the editor entered when the driving goes on

This commit is contained in:
maj00r
2026-10-06 22:19:32 +02:00
parent 084a705452
commit 978b99b7e5
21 changed files with 1329 additions and 15 deletions

View File

@@ -28,6 +28,7 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/lightarray.h"
#include "world/TractionPower.h"
#include "world/Road.h"
#include "world/Sweep.h"
#include "world/RoadPoint.h"
#include "application/application.h"
#include "rendering/renderer.h"
@@ -35,8 +36,19 @@ http://mozilla.org/MPL/2.0/.
#include "utilities/utilities.h"
#include "editor/editorTerrainStreamer.hpp"
namespace simulation {
namespace {
double vehicle_length( std::string const &Folder, std::string const &Type ) {
TMoverParameters probe( 0.0, Type, Type, 0 );
return probe.LoadFIZ( paths::dynamic + Folder + "/" ) ? probe.Dim.L : 0.0;
}
} // namespace
std::shared_ptr<deserializer_state>
state_serializer::deserialize_begin( std::string const &Scenariofile ) {
@@ -123,7 +135,8 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
{ "trainset", &state_serializer::deserialize_trainset },
{ "terrain", &state_serializer::deserialize_terrain },
{ "editorterrain", &state_serializer::deserialize_editorterrain },
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
{ "endtrainset", &state_serializer::deserialize_endtrainset },
{ "reversed", &state_serializer::deserialize_reversed } };
for( auto &function : functionlist ) {
state->functionmap.emplace( function.first, std::bind( function.second, this, std::ref( state->input ), std::ref( state->scratchpad ) ) );
@@ -191,6 +204,7 @@ state_serializer::deserialize_continue(std::shared_ptr<deserializer_state> state
simulation::Roads.create_geometry( Scratchpad );
simulation::Junctions.create_geometry( Scratchpad );
simulation::Roadpoints.create_geometry();
simulation::Sweeps.create_geometry( Scratchpad );
return false;
}
@@ -554,6 +568,20 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
road->create_lanes();
scene::Layers.track( road, { sourcebegin, Input.TokenEnd() } );
}
else if( nodedata.type == "sweep" ) {
auto *sweep { new sweep_node( nodedata ) };
sweep->import(
Input,
( Scratchpad.location.offset.empty() ?
glm::dvec3 { 0.0 } :
glm::dvec3 { Scratchpad.location.offset.top() } ) );
if( false == simulation::Sweeps.insert( sweep ) ) {
ErrorLog( "Bad scenario: duplicate sweep name \"" + sweep->name() + "\" defined in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
}
scene::Groups.insert( scene::Groups.handle(), sweep );
scene::Layers.track( sweep, { sourcebegin, Input.TokenEnd() } );
}
else if( nodedata.type == "junction" ) {
auto *junction { new junction_node( nodedata ) };
@@ -1224,6 +1252,17 @@ include_terrain_file( std::string File, std::string &Includes, scene::scratch_da
} // namespace
void
state_serializer::deserialize_reversed( cParser &Input, scene::scratch_data &Scratchpad ) {
if( false == Scratchpad.trainset.is_open
|| false == Scratchpad.trainset.vehicles.empty() ) {
ErrorLog( "Bad trainset: \"reversed\" has to follow the trainset header, ahead of its vehicles, in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
return;
}
Scratchpad.trainset.reversed = true;
}
void
state_serializer::deserialize_terrain(cParser &Input, scene::scratch_data &Scratchpad)
{
@@ -1312,9 +1351,16 @@ state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &
}
if( vehicleindex > 0 ) {
// from second vehicle on couple it with the previous one
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachNext(
vehicle,
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
if( Scratchpad.trainset.reversed ) {
vehicle->AttachNext(
Scratchpad.trainset.vehicles[ vehicleindex - 1 ],
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
}
else {
Scratchpad.trainset.vehicles[ vehicleindex - 1 ]->AttachNext(
vehicle,
Scratchpad.trainset.couplings[ vehicleindex - 1 ] );
}
}
++vehicleindex;
}
@@ -1494,7 +1540,7 @@ state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scra
loadtype = "";
}
auto *path = simulation::Paths.find( pathname );
auto *path = Scratchpad.trainset.path != nullptr ? Scratchpad.trainset.path : simulation::Paths.find( pathname );
if( path == nullptr ) {
ErrorLog( "Bad scenario: vehicle \"" + Nodedata.name + "\" placed on nonexistent path \"" + pathname + "\" in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
@@ -1502,7 +1548,9 @@ state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scra
return nullptr;
}
if( true == Scratchpad.trainset.vehicles.empty() // jeśli pierwszy pojazd,
auto const reversedset { Scratchpad.trainset.is_open && Scratchpad.trainset.reversed };
if( false == reversedset
&& true == Scratchpad.trainset.vehicles.empty() // jeśli pierwszy pojazd,
&& false == path->m_events0.empty() // tor ma Event0
&& std::abs(velocity) <= 1.f // a skład stoi
&& Scratchpad.trainset.offset >= 0.0 // ale może nie sięgać na owy tor
@@ -1512,23 +1560,34 @@ state_serializer::deserialize_dynamic( cParser &Input, scene::scratch_data &Scra
}
auto *vehicle = new TDynamicObject();
auto const gap { offset == -1.0 ? 0.0 : offset };
auto const turned { ( offset == -1.0 ) != reversedset };
auto const expected { reversedset ? vehicle_length( datafolder, mmdfile ) : 0.0 };
auto const length =
vehicle->Init(
Nodedata.name,
datafolder, skinfile, mmdfile,
path,
offset == -1.0 ? Scratchpad.trainset.offset : Scratchpad.trainset.offset - offset,
reversedset ? Scratchpad.trainset.offset + gap + expected : Scratchpad.trainset.offset - gap,
drivertype,
velocity,
Scratchpad.trainset.name,
loadcount, loadtype,
offset == -1.0,
turned,
params );
if( length != 0.0 && reversedset ) {
if( std::abs( length - expected ) > 0.01 ) {
vehicle->place_on_track( path, Scratchpad.trainset.offset + gap + length, turned );
}
Scratchpad.trainset.offset += length;
}
if( length != 0.0 ) { // zero oznacza błąd
// przesunięcie dla kolejnego, minus bo idziemy w stronę punktu 1
Scratchpad.trainset.offset -= length;
if( false == reversedset ) {
Scratchpad.trainset.offset -= length;
}
// automatically establish permanent connections for couplers which specify them in their definitions
if( coupling != 0
&& vehicle->MoverParameters->Couplers[(offset == -1.0 ? end::front : end::rear)].AllowedFlag & coupling::permanent ) {
@@ -1774,6 +1833,11 @@ state_serializer::export_nodes_to_stream(std::ostream &scmfile, bool Dirty) cons
point->export_as_text( scmfile );
}
}
for( auto const *sweep : Sweeps.sequence() ) {
if( sweep != nullptr && false == sweep->m_editorremoved && sweep->dirty() == Dirty && sweep->group() == null_handle ) {
sweep->export_as_text( scmfile );
}
}
// traction
scmfile << "// traction\n";
for( auto const *traction : Traction.sequence() ) {
@@ -1826,6 +1890,25 @@ TAnimModel *state_serializer::create_model(const std::string &src, const std::st
return cloned;
}
std::vector<TDynamicObject *> state_serializer::insert_trainset(std::string const &Name, TTrack *Path, double const Offset, std::string const &Vehicles, bool const Reversed) {
scene::scratch_data scratch;
scratch.trainset.is_open = true;
scratch.trainset.name = Name;
scratch.trainset.track = Path != nullptr ? Path->name() : std::string{};
scratch.trainset.path = Path;
scratch.trainset.offset = static_cast<float>(Offset);
scratch.trainset.reversed = Reversed;
cParser parser(Vehicles, cParser::buffer_TEXT, Global.asCurrentSceneryPath, Global.bLoadTraction);
auto token { parser.getToken<std::string>() };
while (false == token.empty()) {
if (token == "node") { deserialize_node(parser, scratch); }
token = parser.getToken<std::string>();
}
auto const vehicles { scratch.trainset.vehicles };
if (false == vehicles.empty()) { deserialize_endtrainset(parser, scratch); }
return vehicles;
}
std::pair<int, int> state_serializer::preview_include(std::string const &Directive, scene::layer_context const &Context, scene::layer_handle Layer, scene::instance_handle Instance) {
// statements which take more than a single token, with the tokens ending them
static std::unordered_map<std::string, std::string> const nodeends {