16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 17:29:18 +02:00

post-merge fixes

This commit is contained in:
tmj-fstate
2020-02-20 20:28:32 +01:00
parent 7a0c89f508
commit 330bd3c455
24 changed files with 381 additions and 394 deletions

View File

@@ -3080,8 +3080,8 @@ bool TController::DecBrakeEIM()
bool TController::IncSpeed()
{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
if( true == tsGuardSignal.is_playing() ) {
// jeśli gada, to nie jedziemy
if( fActionTime < 0.0 ) {
// gdy jest nakaz poczekać z jazdą, to nie ruszać
return false;
}
bool OK = true;
@@ -3093,6 +3093,7 @@ bool TController::IncSpeed()
if (mvOccupied->SpringBrake.IsActive && mvOccupied->SpringBrake.Activate) {
mvOccupied->SpringBrakeActivate(false);
}
// Doors() call can potentially adjust fActionTime
if( fActionTime < 0.0 ) {
// gdy jest nakaz poczekać z jazdą, to nie ruszać
return false;
@@ -5717,6 +5718,8 @@ TController::UpdateSituation(double dt) {
// place virtual conductor some distance away
tsGuardSignal.offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } );
tsGuardSignal.play( sound_flags::exclusive );
// NOTE: we can't rely on is_playing() check as sound playback is based on distance from local camera
fActionTime = -5.0; // niech trochę potrzyma
}
else {
// if (iGuardRadio==iRadioChannel) //zgodność kanału
@@ -5727,6 +5730,8 @@ TController::UpdateSituation(double dt) {
tsGuardSignal.owner( pVehicle );
tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } );
tsGuardSignal.play( sound_flags::exclusive );
// NOTE: we can't rely on is_playing() check as sound playback is based on distance from local camera
fActionTime = -5.0; // niech trochę potrzyma
}
}
}
@@ -6984,7 +6989,7 @@ void TController::UpdateDelayFlag() {
void TController::TakeControl( bool const Aidriver, bool const Forcevehiclecheck )
{ // przejęcie kontroli przez AI albo oddanie
if (AIControllFlag == Aidriver)
if ((AIControllFlag == Aidriver) && (!Forcevehiclecheck))
return; // już jest jak ma być
if (Aidriver) //żeby nie wykonywać dwa razy
{ // teraz AI prowadzi
@@ -7145,12 +7150,29 @@ TController::TrackBlock() const {
void TController::MoveTo(TDynamicObject *to)
{ // przesunięcie AI do innego pojazdu (przy zmianie kabiny)
// mvOccupied->CabDeactivisation(); //wyłączenie kabiny w opuszczanym
pVehicle->Mechanik = to->Mechanik; //żeby się zamieniły, jak jest jakieś drugie
if( ( to->Mechanik != nullptr )
&& ( to->Mechanik != this ) ) {
// ai controller thunderdome, there can be only one
if( to->Mechanik->AIControllFlag ) {
if( to->Mechanik->primary() ) {
// take over boss duties
primary( true );
}
SafeDelete( to->Mechanik );
}
else {
// can't quite delete a human
if( AIControllFlag ) {
delete this;
}
return;
}
}
pVehicle->Mechanik = nullptr;
pVehicle = to;
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu
pVehicle->Mechanik = this;
// iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć
};
void TController::ControllingSet()

View File

@@ -2220,17 +2220,6 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset )
if( Type == "" ) { return; }
if( asName == Global.local_start_vehicle ) {
// jeśli pojazd wybrany do prowadzenia
if( MoverParameters->EngineType != TEngineType::Dumb ) {
// wsadzamy tam sterującego
Controller = Humandriver;
}
else {
// w przeciwnym razie trzeba włączyć pokazywanie kabiny
bDisplayCab = true;
}
}
// McZapkie-151102: rozkład jazdy czytany z pliku *.txt z katalogu w którym jest sceneria
if( ( Type == "1" )
|| ( Type == "2" ) ) {
@@ -5539,8 +5528,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
for( auto &bogie : m_bogiesounds ) {
bogie.start( (
bogieidx % 2 ?
Random( 0.0, 30.0 ) :
Random( 50.0, 80.0 ) )
LocalRandom( 0.0, 30.0 ) :
LocalRandom( 50.0, 80.0 ) )
* 0.01 );
++bogieidx;
}

View File

@@ -33,7 +33,6 @@ struct global_settings {
bool ready_to_load { false };
std::time_t starting_timestamp = 0; // starting time, in local timezone
uint32_t random_seed = 0;
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
TCamera pCamera; // parametry kamery
TCamera pDebugCamera;
std::array<Math3D::vector3, 10> FreeCameraInit; // pozycje kamery

View File

@@ -58,13 +58,6 @@ public:
m_itemmap.erase(lookup);
}
uint32_t find_id( std::string const &Name) const {
auto lookup = m_itemmap.find( Name );
return (
lookup != m_itemmap.end() ?
lookup->second :
-1 );
}
void purge (Type_ *Item)
{
for (auto it = m_items.begin(); it != m_items.end(); it++) {

View File

@@ -5827,7 +5827,7 @@ bool TTrain::Update( double const Deltatime )
if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial
{
if (fTachoVelocity > 1) // jedzie
fTachoVelocityJump = fTachoVelocity + (2.0 - Random(3) + Random(3)) * 0.5;
fTachoVelocityJump = fTachoVelocity + (2.0 - LocalRandom(3) + LocalRandom(3)) * 0.5;
else
fTachoVelocityJump = 0; // stoi
fTachoTimer = ff; // juz zmienil
@@ -6049,7 +6049,8 @@ bool TTrain::Update( double const Deltatime )
if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) &&
((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) ||
(mvControlled->TrainType == dt_EZT)) &&
(DynamicObject->Controller == Humandriver)) // hunter-110212: poprawka dla EZT
(DynamicObject->Controller == Humandriver) // hunter-110212: poprawka dla EZT
&& ( false == DynamicObject->Mechanik->AIControllFlag ) )
{ // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/)
if (fConverterTimer < fConverterPrzekaznik)
{
@@ -7496,6 +7497,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
}
// reset view angles
pMechViewAngle = { 0.0, 0.0 };
is_cab_initialized = true; // the attempt may fail, but it's the attempt that counts
bool parse = false;
int cabindex = 0;
DynamicObject->mdKabina = NULL; // likwidacja wskaźnika na dotychczasową kabinę
@@ -7871,7 +7875,6 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
// > Ra: to nie może być tak robione, to zbytnia proteza jest
// indeed, too much hacks...
// TODO: cleanup
TTrain *target_train = simulation::Trains.find(target->name());
if (target_train) {
// let's try to destroy this TTrain and move to already existing one
@@ -7882,18 +7885,22 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->CabDeactivisation();
Occupied()->CabOccupied = 0;
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos();
Occupied()->ScndCtrlPos = 0;
Dynamic()->MechInside = false;
Dynamic()->Controller = AIdriver;
Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} );
Dynamic()->Mechanik->MoveTo(target);
if( Dynamic()->Mechanik ) {
Dynamic()->Mechanik->MoveTo( target );
}
target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress;
target_train->Occupied()->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
target_train->Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
target_train->Dynamic()->MechInside = true;
target_train->Dynamic()->Controller = Humandriver;
target_train->Dynamic()->Controller = ( target_train->Dynamic()->Mechanik ? !target_train->Dynamic()->Mechanik->AIControllFlag : Humandriver );
} else {
target_train->Dynamic()->bDisplayCab = false;
target_train->Dynamic()->ABuSetModelShake( {} );
@@ -7922,20 +7929,24 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->CabDeactivisation();
Occupied()->CabOccupied = 0;
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos();
Occupied()->ScndCtrlPos = 0;
Dynamic()->MechInside = false;
Dynamic()->Controller = AIdriver;
Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} );
Dynamic()->Mechanik->MoveTo(target);
if( Dynamic()->Mechanik ) {
Dynamic()->Mechanik->MoveTo( target );
}
DynamicSet(target);
Occupied()->LimPipePress = Occupied()->PipePress;
Occupied()->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
Dynamic()->MechInside = true;
Dynamic()->Controller = Humandriver;
Dynamic()->Controller = ( Dynamic()->Mechanik ? !Dynamic()->Mechanik->AIControllFlag : Humandriver );
} else {
Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} );
@@ -7953,6 +7964,7 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
// add it back with updated dynamic name
simulation::Trains.insert(this);
}
}
// checks whether specified point is within boundaries of the active cab
@@ -8302,7 +8314,7 @@ void TTrain::set_cab_controls( int const Cab ) {
if( true == mvOccupied->Radio ) {
ggRadioButton.PutValue( 1.f );
}
ggRadioChannelSelector.PutValue( RadioChannel() - 1 );
ggRadioChannelSelector.PutValue( ( Dynamic()->Mechanik ? Dynamic()->Mechanik->iRadioChannel : 1 ) - 1 );
// pantographs
/*
if( mvOccupied->PantSwitchType != "impulse" ) {
@@ -9262,3 +9274,19 @@ void train_table::update(double dt)
}
}
}
TTrain *
train_table::find_id( std::uint16_t const Id ) const {
if( Id == 0 ) { return nullptr; }
for( TTrain *train : m_items ) {
if( !train ) {
continue;
}
if( train->id() == Id ) {
return train;
}
}
return nullptr;
}

View File

@@ -716,6 +716,7 @@ public: // reszta może by?publiczna
// McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc
std::array<TCab, 3> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B)
int iCabn { 0 }; // 0: mid, 1: front, 2: rear
bool is_cab_initialized { false };
// McZapkie: do poruszania sie po kabinie
Math3D::vector3 pMechSittingPosition; // ABu 180404
Math3D::vector3 MirrorPosition( bool lewe );
@@ -773,7 +774,7 @@ private:
float fDieselParams[9][10]; // parametry dla silnikow asynchronicznych
// plays provided sound from position of the radio
void radio_message( sound_source *Message, int const Channel );
inline auto const &RadioChannel() const { return Dynamic()->Mechanik->iRadioChannel; }
inline auto const RadioChannel() const { return ( Dynamic()->Mechanik ? Dynamic()->Mechanik->iRadioChannel : 1 ); }
inline auto &RadioChannel() { return Dynamic()->Mechanik->iRadioChannel; }
inline TDynamicObject *Dynamic() { return DynamicObject; };
inline TDynamicObject const *Dynamic() const { return DynamicObject; };
@@ -794,6 +795,7 @@ private:
class train_table : public basic_table<TTrain> {
public:
void update( double dt );
TTrain *find_id( std::uint16_t const Id ) const;
};
//---------------------------------------------------------------------------

View File

@@ -167,13 +167,26 @@ void eu07_application::queue_quit() {
glfwSetWindowShouldClose(m_windows[0], GLFW_TRUE);
}
bool
eu07_application::is_server() const {
return ( m_network && m_network->servers );
}
bool
eu07_application::is_client() const {
return ( m_network && m_network->client );
}
int
eu07_application::run() {
auto frame{ 0 };
// main application loop
while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty())
{
Timer::subsystem.mainloop_total.start();
glfwPollEvents();
// -------------------------------------------------------------------
// multiplayer command relaying logic can seem a bit complex
@@ -191,6 +204,9 @@ eu07_application::run() {
int loop_remaining = MAX_NETWORK_PER_FRAME;
while (--loop_remaining > 0)
{
#ifdef EU07_DEBUG_NETSYNC
WriteLog( "net: frame " + std::to_string(++frame) + " start", logtype::net );
#endif
command_queue::commands_map commands_to_exec;
command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
double slave_sync;
@@ -272,7 +288,7 @@ eu07_application::run() {
float awaiting = m_network->client->get_awaiting_frames();
// TODO: don't meddle with mode progresbar
m_modes[m_modestack.top()]->set_progress(100.0f, 100.0f * (received - awaiting) / received);
m_modes[m_modestack.top()]->set_progress(100.0f * (received - awaiting) / received);
} else {
m_modes[m_modestack.top()]->set_progress(0.0f, 0.0f);
}
@@ -295,8 +311,6 @@ eu07_application::run() {
if (!GfxRenderer->Render())
return 0;
glfwPollEvents();
if (m_modestack.empty())
return 0;

View File

@@ -92,6 +92,10 @@ public:
generate_sync();
void
queue_quit();
bool
is_server() const;
bool
is_client() const;
private:
// types

View File

@@ -386,7 +386,7 @@ command_relay::post(user_command const Command, double const Param1, double cons
Position = Global.pCamera.Pos;
uint32_t combined_recipient = static_cast<uint32_t>( command.target ) | Recipient;
command_data commanddata({Command, Action, Param1, Param2, Timer::GetDeltaTime(), FreeFlyModeFlag, Position });
command_data commanddata({Command, Action, Param1, Param2, Timer::GetDeltaTime(), Position });
if (Payload)
commanddata.payload = *Payload;

View File

@@ -324,7 +324,6 @@ struct command_data {
double param2;
double time_delta;
bool freefly;
glm::vec3 location;
std::string payload;

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "simulation.h"
#include "simulationtime.h"
#include "simulationenvironment.h"
#include "scene.h"
#include "lightarray.h"
#include "particles.h"
#include "Train.h"
@@ -146,18 +147,19 @@ driver_mode::update() {
double const deltatime = Timer::GetDeltaTime(); // 0.0 gdy pauza
if( Global.iPause == 0 ) {
// jak pauza, to nie ma po co tego przeliczać
simulation::Time.update( deltatime );
}
simulation::State.update_clocks();
simulation::State.update_scripting_interface();
simulation::Environment.update();
if (deltatime != 0.0)
{
// jak pauza, to nie ma po co tego przeliczać
simulation::Time.update( deltatime );
// fixed step, simulation time based updates
// m_primaryupdateaccumulator += dt; // unused for the time being
// m_primaryupdateaccumulator += dt; // unused for the time being
m_secondaryupdateaccumulator += deltatime;
/*
/*
// NOTE: until we have no physics state interpolation during render, we need to rely on the old code,
// as doing fixed step calculations but flexible step render results in ugly mini jitter
// core routines (physics)
@@ -169,20 +171,20 @@ driver_mode::update() {
++updatecount;
m_primaryupdateaccumulator -= m_primaryupdaterate;
}
*/
*/
int updatecount = 1;
if( deltatime > m_primaryupdaterate ) // normalnie 0.01s
{
/*
/*
// NOTE: experimentally disabled physics update cap
auto const iterations = std::ceil(dt / m_primaryupdaterate);
updatecount = std::min( 20, static_cast<int>( iterations ) );
*/
*/
updatecount = std::ceil( deltatime / m_primaryupdaterate );
/*
/*
// NOTE: changing dt wrecks things further down the code. re-acquire proper value later or cleanup here
dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem
*/
*/
}
auto const stepdeltatime { deltatime / updatecount };
// NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations
@@ -229,6 +231,7 @@ driver_mode::update() {
if (!change_train.empty()) {
TTrain *train = simulation::Trains.find(change_train);
if (train) {
Global.local_start_vehicle = change_train;
simulation::Train = train;
InOutKey();
m_relay.post(user_command::aidriverdisable, 0.0, 0.0, GLFW_PRESS, 0);
@@ -245,20 +248,7 @@ driver_mode::update() {
// fixup camera after vehicle switch
CabView();
}
/*
if( Global.changeDynObj ) {
// ABu zmiana pojazdu - przejście do innego
ChangeDynamic();
// move inside, but only if the human is in charge (otherwise we'll get pulled in when ai switches cabs)
if( ( simulation::Train != nullptr )
&& ( simulation::Train->Dynamic() != nullptr )
&& ( simulation::Train->Dynamic()->Mechanik != nullptr )
&& ( simulation::Train->Dynamic()->Mechanik->AIControllFlag == false )
&& ( true == FreeFlyModeFlag ) ) {
InOutKey();
}
}
*/
if( simulation::Train != nullptr )
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
else
@@ -268,6 +258,7 @@ driver_mode::update() {
simulation::Events.update();
simulation::Region->update_events();
simulation::Lights.update();
}
// render time routines follow:
@@ -359,10 +350,10 @@ driver_mode::update() {
// NOTE: particle system runs on simulation time, but needs actual camera position to determine how to update each particle source
simulation::Particles.update();
simulation::is_ready = true;
GfxRenderer->Update( deltarealtime );
simulation::is_ready = simulation::is_ready || ( ( simulation::Train != nullptr ) && ( simulation::Train->is_cab_initialized ) ) || ( Global.local_start_vehicle == "ghostview" );
return true;
}
@@ -375,28 +366,25 @@ driver_mode::enter() {
simulation::Vehicles.find( Global.local_start_vehicle ) :
nullptr ) };
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nPlayerTrain );
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr );
Global.pCamera = Camera;
Global.pDebugCamera = DebugCamera;
FreeFlyModeFlag = true;
DebugCamera = Camera;
if (nPlayerTrain)
{
WriteLog( "Trying to enter player train, \"" + Global.local_start_vehicle + "\"" );
FreeFlyModeFlag = true; // HACK: entervehicle won't work if the simulation thinks we're outside
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0, nPlayerTrain->GetPosition());
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0, nPlayerTrain->GetPosition(), &Global.local_start_vehicle );
change_train = nPlayerTrain->name();
}
else
{
if (Global.local_start_vehicle != "ghostview")
else if (Global.local_start_vehicle != "ghostview")
{
Global.local_start_vehicle = "ghostview";
Error("Bad scenario: failed to locate player train, \"" + Global.local_start_vehicle + "\"" );
}
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
Camera.m_owner = nullptr;
DebugCamera = Camera;
}
// if (!Global.bMultiplayer) //na razie włączone
{ // eventy aktywowane z klawiatury tylko dla jednego użytkownika
@@ -430,8 +418,10 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false;
bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT);
// give the ui first shot at the input processing...
if( true == m_userinterface->on_key( Key, Scancode, Action, Mods ) ) { return; }
if( !anyModifier && true == m_userinterface->on_key( Key, Scancode, Action, Mods ) ) { return; }
// ...if the input is left untouched, pass it on
if( true == m_input.keyboard.key( Key, Action ) ) { return; }
@@ -529,9 +519,9 @@ driver_mode::update_camera( double const Deltatime ) {
Camera.LookAt = controlled->GetPosition() + 0.4 * controlled->VectorUp() * controlled->MoverParameters->Dim.H;
}
else {
TDynamicObject *d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 300, false, false ) );
TDynamicObject *d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 300, false, false ) );
if( !d )
d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 1000, false, false ) ); // dalej szukanie, jesli bliżej nie ma
d = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 1000, false, false ) ); // dalej szukanie, jesli bliżej nie ma
if( d && pDynamicNearest ) {
// jeśli jakiś jest znaleziony wcześniej
@@ -815,106 +805,32 @@ driver_mode::OnKeyDown(int cKey) {
}
case GLFW_KEY_F5: {
// przesiadka do innego pojazdu
if (!FreeFlyModeFlag)
// only available in free fly mode
break;
if( !FreeFlyModeFlag ) { break; }
TDynamicObject *dynamic = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) );
if (dynamic) {
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0);
auto const *targetvehicle { std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 50, false, false ) ) };
change_train = dynamic->name();
}
break;
/*
if( false == FreeFlyModeFlag ) {
// only available in free fly mode
if( targetvehicle == nullptr ) { break; }
if( ( targetvehicle->Mechanik ) &&
( false == targetvehicle->Mechanik->AIControllFlag ) ) {
// for the time being we don't allow more than one person per vehicle
break;
}
TDynamicObject *targetvehicle = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) );
if( targetvehicle != nullptr ) {
if( ( true == DebugModeFlag )
|| ( targetvehicle->MoverParameters->Vel <= 5.0 ) ) {
// works always in debug mode, or for stopped/slow moving vehicles otherwise
if( simulation::Train == nullptr ) {
simulation::Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy
}
if( simulation::Train->Dynamic() != nullptr ) {
// jeśli mielismy pojazd
if( simulation::Train->Dynamic()->Mechanik ) { // na skutek jakiegoś błędu może czasem zniknąć
auto const *currentvehicle { simulation::Train->Dynamic() };
auto const samevehicle { currentvehicle == targetvehicle };
if( samevehicle ) {
// we already control desired vehicle so don't overcomplicate things
InOutKey(); // do kabiny
break;
}
auto const sameconsist {
( targetvehicle->ctOwner == currentvehicle->Mechanik )
|| ( targetvehicle->ctOwner == currentvehicle->ctOwner ) };
auto const isincharge { currentvehicle->Mechanik->primary() };
auto const aidriveractive { currentvehicle->Mechanik->AIControllFlag };
if( !sameconsist && isincharge ) {
// oddajemy dotychczasowy AI
simulation::Train->Dynamic()->Mechanik->TakeControl( true );
}
if( ( !sameconsist ) // we leave behind an ai driver which should be preserved
|| ( aidriveractive ) // we want to preserve existing ai driver
|| ( targetvehicle->Mechanik != nullptr ) ) { // .changedynobj swaps drivers but we want a takeover not a swap
if( sameconsist && !aidriveractive ) {
// we will be taking over controller in the target vehicle, so get rid of the old one
// unless it's an active ai in which case leave it running
SafeDelete( simulation::Train->Dynamic()->Mechanik );
}
// HACK: by resetting owned vehicle we can reuse dynamic==nullptr code branch below
// TODO: refactor into utility method
simulation::Train->DynamicSet( nullptr );
}
else {
// we can simply move the 'human' controller to the new vehicle
Global.changeDynObj = targetvehicle;
// TODO: choose active cab based on camera's location relative to vehicle's location
// Global.changeDynObj->MoverParameters->CabOccupied = (
// Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
// -1 :
// 1 );
}
}
}
if( simulation::Train->Dynamic() == nullptr ) {
// jeśli niczym jeszcze nie jeździlismy
if( simulation::Train->Init( targetvehicle ) ) {
// przejmujemy sterowanie
if( true == Global.ctrlState ) {
// make sure we can take over the consist
// TODO: remove ctrl key mode once manual cab (de)activation is in place
simulation::Train->Dynamic()->Mechanik->primary( true );
}
simulation::Train->Dynamic()->Mechanik->TakeControl( false, true );
if( true == simulation::Train->Dynamic()->Mechanik->primary() ) {
simulation::Train->Occupied()->CabDeactivisation( true ); // potentially left active
// simulation::Train->Occupied()->CabOccupied = simulation::Train->Occupied()->CabActive;
simulation::Train->Occupied()->CabActivisation();
}
InOutKey(); // do kabiny
}
else {
SafeDelete( simulation::Train ); // i nie ma czym sterować
}
}
}
m_relay.post(
user_command::entervehicle,
( Global.ctrlState ? GLFW_MOD_CONTROL : 0 ), // TODO: remove ctrl key mode once manual cab (de)activation is in place,
( simulation::Train ? simulation::Train->id() : 0 ),
GLFW_PRESS,
0,
targetvehicle->GetPosition(),
&targetvehicle->name() );
change_train = targetvehicle->name();
}
break;
*/
}
case GLFW_KEY_F6: {
// przyspieszenie symulacji do testowania scenerii... uwaga na FPS!
@@ -1176,67 +1092,6 @@ driver_mode::CabView() {
train->pMechOffset = Camera.m_owneroffset;
}
void
driver_mode::ChangeDynamic() {
auto *train { simulation::Train };
if( train == nullptr ) { return; }
auto *vehicle { train->Dynamic() };
auto *occupied { train->Occupied() };
auto *driver { vehicle->Mechanik };
// Ra: to nie może być tak robione, to zbytnia proteza jest
if( driver ) {
// AI może sobie samo pójść
if( false == driver->AIControllFlag ) {
// tylko jeśli ręcznie prowadzony
// jeśli prowadzi AI, to mu nie robimy dywersji!
occupied->CabDeactivisation();
occupied->CabOccupied = 0;
occupied->BrakeLevelSet( occupied->Handle->GetPos( bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016
occupied->MainCtrlPos = occupied->MainCtrlNoPowerPos();
occupied->ScndCtrlPos = 0;
vehicle->MechInside = false;
vehicle->Controller = AIdriver;
}
}
TDynamicObject *temp = Global.changeDynObj;
vehicle->bDisplayCab = false;
vehicle->ABuSetModelShake( {} );
if( driver ) // AI może sobie samo pójść
if( false == driver->AIControllFlag ) {
// tylko jeśli ręcznie prowadzony
// przsunięcie obiektu zarządzającego
driver->MoveTo( temp );
}
train->DynamicSet( temp );
// update helpers
train = simulation::Train;
vehicle = train->Dynamic();
occupied = train->Occupied();
driver = vehicle->Mechanik;
Global.local_start_vehicle = vehicle->name();
if( driver ) // AI może sobie samo pójść
if( false == driver->AIControllFlag ) // tylko jeśli ręcznie prowadzony
{
occupied->LimPipePress = occupied->PipePress;
occupied->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
vehicle->MechInside = true;
vehicle->Controller = Humandriver;
}
train->InitializeCab(
occupied->CabActive,
vehicle->asBaseDir + occupied->TypeName + ".mmd" );
if( false == FreeFlyModeFlag ) {
vehicle->bDisplayCab = true;
vehicle->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem?
CabView(); // na pozycję mecha
}
Global.changeDynObj = nullptr;
}
void
driver_mode::InOutKey()
{ // przełączenie widoku z kabiny na zewnętrzny i odwrotnie

View File

@@ -91,7 +91,6 @@ private:
void update_camera( const double Deltatime );
// handles vehicle change flag
void OnKeyDown( int cKey );
void ChangeDynamic();
void InOutKey();
void CabView();
void ExternalView();

View File

@@ -181,8 +181,14 @@ driver_ui::render_() {
}
if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
ImGui::CloseCurrentPopup();
// NOTE: server shuts down entire network, client or standalone instance only shuts down self
if( Application.is_server() ) {
command_relay commandrelay;
commandrelay.post(user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0);
commandrelay.post( user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0 );
}
else {
Application.queue_quit();
}
}
ImGui::EndPopup();
}

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "driveruipanels.h"
#include "Globals.h"
#include "application.h"
#include "translation.h"
#include "simulation.h"
#include "simulationtime.h"
@@ -564,34 +565,45 @@ bool
debug_panel::render_section_scenario() {
if( false == render_section( "Scenario", m_scenariolines ) ) { return false; }
if( Application.is_client() ) {
// NOTE: simulation clients can't adjust scenarion state, this is reserved for the server/standalone instance
return true;
}
// fog slider
{
auto fogrange = std::log( Global.fFogEnd );
if( ImGui::SliderFloat(
( to_string( std::exp( fogrange ), 0, 5 ) + " m###fogend" ).c_str(), &fogrange, std::log( 10.0f ), std::log( 25000.0f ), "Fog distance" ) ) {
Global.fFogEnd = clamp( std::exp( fogrange ), 10.0f, 25000.0f );
command_relay relay;
relay.post(
user_command::setweather,
clamp( std::exp( fogrange ), 10.0f, 25000.0f ),
Global.Overcast,
GLFW_PRESS, 0 );
}
}
// cloud cover slider
{
if( ImGui::SliderFloat(
( to_string( Global.Overcast, 2, 5 ) + " (" + Global.Weather + ")###overcast" ).c_str(), &Global.Overcast, 0.0f, 2.0f, "Cloud cover" ) ) {
Global.Overcast = clamp( Global.Overcast, 0.0f, 2.0f );
simulation::Environment.compute_weather();
command_relay relay;
relay.post(
user_command::setweather,
Global.fFogEnd,
clamp( Global.Overcast, 0.0f, 2.0f ),
GLFW_PRESS, 0 );
}
}
// day of year slider
{
if( ImGui::SliderFloat( ( to_string( Global.fMoveLight, 0, 5 ) + " (" + Global.Season + ")###movelight" ).c_str(), &Global.fMoveLight, 0.0f, 364.0f, "Day of year" ) ) {
Global.fMoveLight = clamp( Global.fMoveLight, 0.0f, 365.0f );
auto const weather{ Global.Weather };
simulation::Environment.compute_season( Global.fMoveLight );
simulation::Time.init();
if( weather != Global.Weather ) {
// HACK: force re-calculation of precipitation
Global.Overcast = clamp( Global.Overcast - 0.0001f, 0.0f, 2.0f );
}
if( ImGui::SliderFloat(
( to_string( Global.fMoveLight, 0, 5 ) + " (" + Global.Season + ")###movelight" ).c_str(), &Global.fMoveLight, 0.0f, 364.0f, "Day of year" ) ) {
command_relay relay;
relay.post(
user_command::setdatetime,
clamp( Global.fMoveLight, 0.0f, 365.0f ),
simulation::Time.data().wHour * 60 + simulation::Time.data().wMinute,
GLFW_PRESS, 0 );
}
}
// time of day slider
@@ -605,15 +617,15 @@ debug_panel::render_section_scenario() {
+ ":"
+ std::string( to_string( int( 100 + simulation::Time.data().wMinute ) ).substr( 1, 2 ) ) ) };
if( ImGui::SliderInt( ( timestring + " (" + Global.Period + ")###simulationtime" ).c_str(), &time, 0, 1439, "Time of day" ) ) {
time = clamp( time, 0, 1439 );
auto const hour{ std::floor( time / 60 ) };
auto const minute{ time % 60 };
simulation::Time.data().wHour = hour;
simulation::Time.data().wMinute = minute;
command_relay relay;
relay.post(
user_command::setdatetime,
Global.fMoveLight,
clamp( time, 0, 1439 ),
GLFW_PRESS, 0 );
}
}
return true;
}

View File

@@ -18,12 +18,16 @@ void network::server_hello::serialize(std::ostream &stream) const
{
sn_utils::ls_uint32(stream, seed);
sn_utils::ls_int64(stream, timestamp);
sn_utils::ls_int64(stream, config);
sn_utils::s_str(stream, scenario);
}
void network::server_hello::deserialize(std::istream &stream)
{
seed = sn_utils::ld_uint32(stream);
timestamp = sn_utils::ld_int64(stream);
config = sn_utils::ld_int64(stream);
scenario = sn_utils::d_str(stream);
}
void ::network::request_command::serialize(std::ostream &stream) const
@@ -41,7 +45,6 @@ void ::network::request_command::serialize(std::ostream &stream) const
sn_utils::ls_float64(stream, data.param2);
sn_utils::ls_float64(stream, data.time_delta);
sn_utils::s_bool(stream, data.freefly);
sn_utils::s_vec3(stream, data.location);
sn_utils::s_str(stream, data.payload);
@@ -67,7 +70,6 @@ void network::request_command::deserialize(std::istream &stream)
data.param2 = sn_utils::ld_float64(stream);
data.time_delta = sn_utils::ld_float64(stream);
data.freefly = sn_utils::d_bool(stream);
data.location = sn_utils::d_vec3(stream);
data.payload = sn_utils::d_str(stream);

View File

@@ -40,6 +40,8 @@ struct server_hello : public message
uint32_t seed;
int64_t timestamp;
int64_t config;
std::string scenario;
virtual void serialize(std::ostream &stream) const override;
virtual void deserialize(std::istream &stream) override;

View File

@@ -7,6 +7,8 @@
#include "application.h"
#include "Globals.h"
std::uint32_t const EU07_NETWORK_VERSION = 2;
namespace network {
backend_list_t& backend_list() {
@@ -40,7 +42,7 @@ void network::connection::connected()
if (is_client) {
client_hello msg;
msg.version = 1;
msg.version = EU07_NETWORK_VERSION;
msg.start_packet = packet_counter;
send_message(msg);
}
@@ -125,7 +127,7 @@ void network::server::handle_message(std::shared_ptr<connection> conn, const mes
if (msg.type == message::CLIENT_HELLO) {
auto cmd = dynamic_cast<const client_hello&>(msg);
if (cmd.version != 1 // wrong version
if (cmd.version != EU07_NETWORK_VERSION // wrong version
|| !Global.ready_to_load) { // not ready yet
conn->disconnect();
return;
@@ -134,6 +136,8 @@ void network::server::handle_message(std::shared_ptr<connection> conn, const mes
server_hello reply;
reply.seed = Global.random_seed;
reply.timestamp = Global.starting_timestamp;
reply.config = 0; // TODO: pass bitfield with state of relevant setting switches
reply.scenario = Global.SceneryFile;
conn->state = connection::CATCHING_UP;
conn->backbuffer = backbuffer;
conn->backbuffer_pos = 0;
@@ -244,6 +248,8 @@ void network::client::handle_message(std::shared_ptr<connection> conn, const mes
Global.random_seed = cmd.seed;
Global.random_engine.seed(Global.random_seed);
Global.starting_timestamp = cmd.timestamp;
// TODO: configure simulation settings according to received cmd.config
Global.SceneryFile = cmd.scenario;
Global.ready_to_load = true;
} else if (Global.random_seed != cmd.seed) {
ErrorLog("net: seed mismatch", logtype::net);

View File

@@ -58,20 +58,20 @@ smoke_source::particle_emitter::deserialize( cParser &Input ) {
void
smoke_source::particle_emitter::initialize( smoke_particle &Particle ) {
auto const polarangle { glm::radians( Random( inclination[ value_limit::min ], inclination[ value_limit::max ] ) ) }; // theta
auto const azimuthalangle { glm::radians( Random( -180, 180 ) ) }; // phi
auto const polarangle { glm::radians( LocalRandom( inclination[ value_limit::min ], inclination[ value_limit::max ] ) ) }; // theta
auto const azimuthalangle { glm::radians( LocalRandom( -180, 180 ) ) }; // phi
// convert spherical coordinates to opengl coordinates
auto const launchvector { glm::vec3(
std::sin( polarangle ) * std::sin( azimuthalangle ) * -1,
std::cos( polarangle ),
std::sin( polarangle ) * std::cos( azimuthalangle ) ) };
auto const launchvelocity { static_cast<float>( Random( velocity[ value_limit::min ], velocity[ value_limit::max ] ) ) };
auto const launchvelocity { static_cast<float>( LocalRandom( velocity[ value_limit::min ], velocity[ value_limit::max ] ) ) };
Particle.velocity = launchvector * launchvelocity;
Particle.rotation = glm::radians( Random( 0, 360 ) );
Particle.size = Random( size[ value_limit::min ], size[ value_limit::max ] );
Particle.opacity = Random( opacity[ value_limit::min ], opacity[ value_limit::max ] ) / Global.SmokeFidelity;
Particle.rotation = glm::radians( LocalRandom( 0, 360 ) );
Particle.size = LocalRandom( size[ value_limit::min ], size[ value_limit::max ] );
Particle.opacity = LocalRandom( opacity[ value_limit::min ], opacity[ value_limit::max ] ) / Global.SmokeFidelity;
Particle.age = 0;
}

View File

@@ -36,7 +36,6 @@ scenarioloader_mode::init() {
// mode-specific update of simulation data. returns: false on error, true otherwise
bool
scenarioloader_mode::update() {
if (!Global.ready_to_load)
// waiting for network connection
return true;
@@ -44,6 +43,7 @@ scenarioloader_mode::update() {
if (!state) {
WriteLog("using simulation seed: " + std::to_string(Global.random_seed), logtype::generic);
Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." );
timestart = std::chrono::system_clock::now();
@@ -78,7 +78,7 @@ scenarioloader_mode::enter() {
simulation::is_ready = false;
m_userinterface->set_background( "logo" );
Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
Application.set_title( Global.AppName );
m_userinterface->set_progress();
m_userinterface->set_progress( "Loading scenery / Wczytywanie scenerii" );
GfxRenderer->Render();

View File

@@ -59,6 +59,7 @@ struct scratch_data {
std::string name;
bool initialized { false };
bool time_initialized { false };
};
// basic element of rudimentary partitioning scheme for the section. fixed size, no further subdivision

View File

@@ -218,27 +218,57 @@ void state_manager::process_commands() {
if (commanddata.command == user_command::entervehicle) {
// przesiadka do innego pojazdu
if (!commanddata.freefly)
// only available in free fly mode
// NOTE: because malformed scenario can have vehicle name duplicates we first try to locate vehicle in world, with name search as fallback
TDynamicObject *targetvehicle = std::get<TDynamicObject *>( simulation::Region->find_vehicle( commanddata.location, 50, false, false ) );
if( ( targetvehicle == nullptr ) || ( targetvehicle->name() != commanddata.payload ) ) {
targetvehicle = simulation::Vehicles.find( commanddata.payload );
}
if (!targetvehicle)
continue;
TDynamicObject *dynamic = std::get<TDynamicObject *>( simulation::Region->find_vehicle( commanddata.location, 50, false, false ) );
auto *senderlocaltrain { simulation::Trains.find_id( static_cast<std::uint16_t>( commanddata.param2 ) ) };
if( senderlocaltrain ) {
auto *currentvehicle { senderlocaltrain->Dynamic() };
auto const samevehicle { currentvehicle == targetvehicle };
if (!dynamic)
if( samevehicle ) {
// we already control desired vehicle so don't overcomplicate things
continue;
}
auto const sameconsist{
( targetvehicle->ctOwner == currentvehicle->Mechanik )
|| ( targetvehicle->ctOwner == currentvehicle->ctOwner ) };
auto const isincharge{ currentvehicle->Mechanik->primary() };
auto const aidriveractive{ currentvehicle->Mechanik->AIControllFlag };
// TODO: support for primary mode request passed as commanddata.param1
if( !sameconsist && isincharge ) {
// oddajemy dotychczasowy AI
currentvehicle->Mechanik->TakeControl( true );
}
if( sameconsist && !aidriveractive ) {
// since we're consist owner we can simply move to the destination vehicle
senderlocaltrain->MoveToVehicle( targetvehicle );
senderlocaltrain->Dynamic()->Mechanik->TakeControl( false, true );
}
}
auto *train { simulation::Trains.find( targetvehicle->name() ) };
TTrain *train = simulation::Trains.find(dynamic->name());
if (train)
continue;
train = new TTrain();
if (train->Init(dynamic)) {
if (train->Init(targetvehicle)) {
simulation::Trains.insert(train);
}
else {
delete train;
train = nullptr;
}
}
if (commanddata.command == user_command::queueevent) {
@@ -268,10 +298,15 @@ void state_manager::process_commands() {
if (commanddata.command == user_command::setdatetime) {
int yearday = std::round(commanddata.param1);
int minute = std::round(commanddata.param2 * 60.0);
int minute = std::round(commanddata.param2);
simulation::Time.set_time(yearday, minute);
auto const weather { Global.Weather };
simulation::Environment.compute_season(yearday);
if( weather != Global.Weather ) {
// HACK: force re-calculation of precipitation
Global.Overcast = clamp( Global.Overcast - 0.0001f, 0.0f, 2.0f );
}
}
if (commanddata.command == user_command::setweather) {
@@ -394,6 +429,7 @@ void state_manager::process_commands() {
}
if (commanddata.command == user_command::quitsimulation) {
// TBD: allow clients to go into offline mode?
Application.queue_quit();
}

View File

@@ -320,6 +320,9 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc
simulation::Events.InitLaunchers();
simulation::Memory.InitCells();
if (!Scratchpad.time_initialized)
init_time();
Scratchpad.initialized = true;
}
@@ -628,20 +631,14 @@ state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratch
>> time.wHour
>> time.wMinute;
if( true == Global.ScenarioTimeCurrent ) {
// calculate time shift required to match scenario time with local clock
auto timenow = std::time( 0 );
auto const *localtime = std::localtime( &timenow );
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
else if( false == std::isnan( Global.ScenarioTimeOverride ) ) {
// scenario time override takes precedence over scenario time offset
Global.ScenarioTimeOffset = ( ( Global.ScenarioTimeOverride * 60 ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
// remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically
// anything else left in the section has no defined meaning
skip_until( Input, "endtime" );
if (!Scratchpad.time_initialized)
Scratchpad.time_initialized = true;
init_time();
}
void
@@ -974,6 +971,19 @@ state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratc
return sound;
}
void state_serializer::init_time() {
auto &time = simulation::Time.data();
if( true == Global.ScenarioTimeCurrent ) {
// calculate time shift required to match scenario time with local clock
auto const *localtime = std::gmtime( &Global.starting_timestamp );
Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
else if( false == std::isnan( Global.ScenarioTimeOverride ) ) {
// scenario time override takes precedence over scenario time offset
Global.ScenarioTimeOffset = ( ( Global.ScenarioTimeOverride * 60 ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f;
}
}
// skips content of stream until specified token
void
state_serializer::skip_until( cParser &Input, std::string const &Token ) {

View File

@@ -76,6 +76,7 @@ private:
TAnimModel * deserialize_model( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
TDynamicObject * deserialize_dynamic( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
sound_source * deserialize_sound( cParser &Input, scene::scratch_data &Scratchpad, scene::node_data const &Nodedata );
void init_time();
// skips content of stream until specified token
void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset

View File

@@ -27,8 +27,10 @@ Copyright (C) 2007-2014 Maciej Cierniak
#include "Globals.h"
#include "parser.h"
#include "Logs.h"
bool DebugModeFlag = false;
bool FreeFlyModeFlag = true;
bool FreeFlyModeFlag = false;
bool EditorModeFlag = false;
bool DebugCameraFlag = false;
bool DebugTractionFlag = false;
@@ -107,6 +109,11 @@ bool ClearFlag( int &Flag, int const Value ) {
double Random(double a, double b)
{
uint32_t val = Global.random_engine();
#ifdef EU07_DEBUG_NETSYNC
auto const value = interpolate( a, b, (double)val / Global.random_engine.max() );
WriteLog( "random: [" + to_string(a,0) + "-" + to_string(b,0) + "] = " + std::to_string( value ) );
return value;
#endif
return interpolate(a, b, (double)val / Global.random_engine.max());
}