16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 19:09: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() bool TController::IncSpeed()
{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać { // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
if( true == tsGuardSignal.is_playing() ) { if( fActionTime < 0.0 ) {
// jeśli gada, to nie jedziemy // gdy jest nakaz poczekać z jazdą, to nie ruszać
return false; return false;
} }
bool OK = true; bool OK = true;
@@ -3093,6 +3093,7 @@ bool TController::IncSpeed()
if (mvOccupied->SpringBrake.IsActive && mvOccupied->SpringBrake.Activate) { if (mvOccupied->SpringBrake.IsActive && mvOccupied->SpringBrake.Activate) {
mvOccupied->SpringBrakeActivate(false); mvOccupied->SpringBrakeActivate(false);
} }
// Doors() call can potentially adjust fActionTime
if( fActionTime < 0.0 ) { if( fActionTime < 0.0 ) {
// gdy jest nakaz poczekać z jazdą, to nie ruszać // gdy jest nakaz poczekać z jazdą, to nie ruszać
return false; return false;
@@ -5717,6 +5718,8 @@ TController::UpdateSituation(double dt) {
// place virtual conductor some distance away // place virtual conductor some distance away
tsGuardSignal.offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } ); tsGuardSignal.offset( { pVehicle->MoverParameters->Dim.W * -0.75f, 1.7f, std::min( -20.0, -0.2 * fLength ) } );
tsGuardSignal.play( sound_flags::exclusive ); 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 { else {
// if (iGuardRadio==iRadioChannel) //zgodność kanału // if (iGuardRadio==iRadioChannel) //zgodność kanału
@@ -5727,6 +5730,8 @@ TController::UpdateSituation(double dt) {
tsGuardSignal.owner( pVehicle ); tsGuardSignal.owner( pVehicle );
tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } ); tsGuardSignal.offset( { 0.f, 2.f, pVehicle->MoverParameters->Dim.L * 0.4f * ( pVehicle->MoverParameters->CabOccupied < 0 ? -1 : 1 ) } );
tsGuardSignal.play( sound_flags::exclusive ); 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 ) void TController::TakeControl( bool const Aidriver, bool const Forcevehiclecheck )
{ // przejęcie kontroli przez AI albo oddanie { // przejęcie kontroli przez AI albo oddanie
if (AIControllFlag == Aidriver) if ((AIControllFlag == Aidriver) && (!Forcevehiclecheck))
return; // już jest jak ma być return; // już jest jak ma być
if (Aidriver) //żeby nie wykonywać dwa razy if (Aidriver) //żeby nie wykonywać dwa razy
{ // teraz AI prowadzi { // teraz AI prowadzi
@@ -7145,12 +7150,29 @@ TController::TrackBlock() const {
void TController::MoveTo(TDynamicObject *to) void TController::MoveTo(TDynamicObject *to)
{ // przesunięcie AI do innego pojazdu (przy zmianie kabiny) { // przesunięcie AI do innego pojazdu (przy zmianie kabiny)
// mvOccupied->CabDeactivisation(); //wyłączenie kabiny w opuszczanym if( ( to->Mechanik != nullptr )
pVehicle->Mechanik = to->Mechanik; //żeby się zamieniły, jak jest jakieś drugie && ( 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; pVehicle = to;
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu ControllingSet(); // utworzenie połączenia do sterowanego pojazdu
pVehicle->Mechanik = this; pVehicle->Mechanik = this;
// iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć
}; };
void TController::ControllingSet() void TController::ControllingSet()

View File

@@ -2220,17 +2220,6 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset )
if( Type == "" ) { return; } 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 // McZapkie-151102: rozkład jazdy czytany z pliku *.txt z katalogu w którym jest sceneria
if( ( Type == "1" ) if( ( Type == "1" )
|| ( Type == "2" ) ) { || ( Type == "2" ) ) {
@@ -5539,8 +5528,8 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
for( auto &bogie : m_bogiesounds ) { for( auto &bogie : m_bogiesounds ) {
bogie.start( ( bogie.start( (
bogieidx % 2 ? bogieidx % 2 ?
Random( 0.0, 30.0 ) : LocalRandom( 0.0, 30.0 ) :
Random( 50.0, 80.0 ) ) LocalRandom( 50.0, 80.0 ) )
* 0.01 ); * 0.01 );
++bogieidx; ++bogieidx;
} }

View File

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

View File

@@ -58,13 +58,6 @@ public:
m_itemmap.erase(lookup); 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) void purge (Type_ *Item)
{ {
for (auto it = m_items.begin(); it != m_items.end(); it++) { 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 (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial
{ {
if (fTachoVelocity > 1) // jedzie 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 else
fTachoVelocityJump = 0; // stoi fTachoVelocityJump = 0; // stoi
fTachoTimer = ff; // juz zmienil fTachoTimer = ff; // juz zmienil
@@ -6049,7 +6049,8 @@ bool TTrain::Update( double const Deltatime )
if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) && if ((mvControlled->CompressorFlag == true) && (mvControlled->CompressorPower == 1) &&
((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) || ((mvControlled->EngineType == TEngineType::ElectricSeriesMotor) ||
(mvControlled->TrainType == dt_EZT)) && (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/) { // hunter-091012: poprawka (zmiana warunku z CompressorPower /rozne od 0/ na /rowne 1/)
if (fConverterTimer < fConverterPrzekaznik) if (fConverterTimer < fConverterPrzekaznik)
{ {
@@ -7496,6 +7497,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
} }
// reset view angles // reset view angles
pMechViewAngle = { 0.0, 0.0 }; pMechViewAngle = { 0.0, 0.0 };
is_cab_initialized = true; // the attempt may fail, but it's the attempt that counts
bool parse = false; bool parse = false;
int cabindex = 0; int cabindex = 0;
DynamicObject->mdKabina = NULL; // likwidacja wskaźnika na dotychczasową kabinę 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 // > Ra: to nie może być tak robione, to zbytnia proteza jest
// indeed, too much hacks... // indeed, too much hacks...
// TODO: cleanup // TODO: cleanup
TTrain *target_train = simulation::Trains.find(target->name()); TTrain *target_train = simulation::Trains.find(target->name());
if (target_train) { if (target_train) {
// let's try to destroy this TTrain and move to already existing one // let's try to destroy this TTrain and move to already existing one
@@ -7882,18 +7885,22 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->CabDeactivisation(); Occupied()->CabDeactivisation();
Occupied()->CabOccupied = 0; Occupied()->CabOccupied = 0;
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016 Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
Dynamic()->MechInside = false; Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos();
Occupied()->ScndCtrlPos = 0;
Dynamic()->MechInside = false;
Dynamic()->Controller = AIdriver; Dynamic()->Controller = AIdriver;
Dynamic()->bDisplayCab = false; Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} ); Dynamic()->ABuSetModelShake( {} );
Dynamic()->Mechanik->MoveTo(target); if( Dynamic()->Mechanik ) {
Dynamic()->Mechanik->MoveTo( target );
}
target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress; 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()->MechInside = true;
target_train->Dynamic()->Controller = Humandriver; target_train->Dynamic()->Controller = ( target_train->Dynamic()->Mechanik ? !target_train->Dynamic()->Mechanik->AIControllFlag : Humandriver );
} else { } else {
target_train->Dynamic()->bDisplayCab = false; target_train->Dynamic()->bDisplayCab = false;
target_train->Dynamic()->ABuSetModelShake( {} ); target_train->Dynamic()->ABuSetModelShake( {} );
@@ -7922,20 +7929,24 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->CabDeactivisation(); Occupied()->CabDeactivisation();
Occupied()->CabOccupied = 0; Occupied()->CabOccupied = 0;
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016 Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
Dynamic()->MechInside = false; Occupied()->MainCtrlPos = Occupied()->MainCtrlNoPowerPos();
Occupied()->ScndCtrlPos = 0;
Dynamic()->MechInside = false;
Dynamic()->Controller = AIdriver; Dynamic()->Controller = AIdriver;
Dynamic()->bDisplayCab = false; Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} ); Dynamic()->ABuSetModelShake( {} );
Dynamic()->Mechanik->MoveTo(target); if( Dynamic()->Mechanik ) {
Dynamic()->Mechanik->MoveTo( target );
}
DynamicSet(target); DynamicSet(target);
Occupied()->LimPipePress = Occupied()->PipePress; 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()->MechInside = true;
Dynamic()->Controller = Humandriver; Dynamic()->Controller = ( Dynamic()->Mechanik ? !Dynamic()->Mechanik->AIControllFlag : Humandriver );
} else { } else {
Dynamic()->bDisplayCab = false; Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} ); Dynamic()->ABuSetModelShake( {} );
@@ -7953,6 +7964,7 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
// add it back with updated dynamic name // add it back with updated dynamic name
simulation::Trains.insert(this); simulation::Trains.insert(this);
} }
} }
// checks whether specified point is within boundaries of the active cab // 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 ) { if( true == mvOccupied->Radio ) {
ggRadioButton.PutValue( 1.f ); ggRadioButton.PutValue( 1.f );
} }
ggRadioChannelSelector.PutValue( RadioChannel() - 1 ); ggRadioChannelSelector.PutValue( ( Dynamic()->Mechanik ? Dynamic()->Mechanik->iRadioChannel : 1 ) - 1 );
// pantographs // pantographs
/* /*
if( mvOccupied->PantSwitchType != "impulse" ) { 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 // McZapkie: opis kabiny - obszar poruszania sie mechanika oraz zajetosc
std::array<TCab, 3> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B) std::array<TCab, 3> Cabine; // przedzial maszynowy, kabina 1 (A), kabina 2 (B)
int iCabn { 0 }; // 0: mid, 1: front, 2: rear int iCabn { 0 }; // 0: mid, 1: front, 2: rear
bool is_cab_initialized { false };
// McZapkie: do poruszania sie po kabinie // McZapkie: do poruszania sie po kabinie
Math3D::vector3 pMechSittingPosition; // ABu 180404 Math3D::vector3 pMechSittingPosition; // ABu 180404
Math3D::vector3 MirrorPosition( bool lewe ); Math3D::vector3 MirrorPosition( bool lewe );
@@ -773,7 +774,7 @@ private:
float fDieselParams[9][10]; // parametry dla silnikow asynchronicznych float fDieselParams[9][10]; // parametry dla silnikow asynchronicznych
// plays provided sound from position of the radio // plays provided sound from position of the radio
void radio_message( sound_source *Message, int const Channel ); 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 auto &RadioChannel() { return Dynamic()->Mechanik->iRadioChannel; }
inline TDynamicObject *Dynamic() { return DynamicObject; }; inline TDynamicObject *Dynamic() { return DynamicObject; };
inline TDynamicObject const *Dynamic() const { return DynamicObject; }; inline TDynamicObject const *Dynamic() const { return DynamicObject; };
@@ -794,6 +795,7 @@ private:
class train_table : public basic_table<TTrain> { class train_table : public basic_table<TTrain> {
public: public:
void update( double dt ); 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); 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 int
eu07_application::run() { eu07_application::run() {
auto frame{ 0 };
// main application loop // main application loop
while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty()) while (!glfwWindowShouldClose( m_windows.front() ) && !m_modestack.empty())
{ {
Timer::subsystem.mainloop_total.start(); Timer::subsystem.mainloop_total.start();
glfwPollEvents();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// multiplayer command relaying logic can seem a bit complex // multiplayer command relaying logic can seem a bit complex
@@ -191,6 +204,9 @@ eu07_application::run() {
int loop_remaining = MAX_NETWORK_PER_FRAME; int loop_remaining = MAX_NETWORK_PER_FRAME;
while (--loop_remaining > 0) 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 commands_to_exec;
command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue(); command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
double slave_sync; double slave_sync;
@@ -272,7 +288,7 @@ eu07_application::run() {
float awaiting = m_network->client->get_awaiting_frames(); float awaiting = m_network->client->get_awaiting_frames();
// TODO: don't meddle with mode progresbar // 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 { } else {
m_modes[m_modestack.top()]->set_progress(0.0f, 0.0f); m_modes[m_modestack.top()]->set_progress(0.0f, 0.0f);
} }
@@ -295,8 +311,6 @@ eu07_application::run() {
if (!GfxRenderer->Render()) if (!GfxRenderer->Render())
return 0; return 0;
glfwPollEvents();
if (m_modestack.empty()) if (m_modestack.empty())
return 0; return 0;

View File

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

View File

@@ -386,7 +386,7 @@ command_relay::post(user_command const Command, double const Param1, double cons
Position = Global.pCamera.Pos; Position = Global.pCamera.Pos;
uint32_t combined_recipient = static_cast<uint32_t>( command.target ) | Recipient; 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) if (Payload)
commanddata.payload = *Payload; commanddata.payload = *Payload;

View File

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

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "simulation.h" #include "simulation.h"
#include "simulationtime.h" #include "simulationtime.h"
#include "simulationenvironment.h" #include "simulationenvironment.h"
#include "scene.h"
#include "lightarray.h" #include "lightarray.h"
#include "particles.h" #include "particles.h"
#include "Train.h" #include "Train.h"
@@ -146,129 +147,119 @@ driver_mode::update() {
double const deltatime = Timer::GetDeltaTime(); // 0.0 gdy pauza 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_clocks();
simulation::State.update_scripting_interface(); simulation::State.update_scripting_interface();
simulation::Environment.update(); 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 // 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; m_secondaryupdateaccumulator += deltatime;
/* /*
// NOTE: until we have no physics state interpolation during render, we need to rely on the old code, // 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 // as doing fixed step calculations but flexible step render results in ugly mini jitter
// core routines (physics) // core routines (physics)
int updatecount = 0; int updatecount = 0;
while( ( m_primaryupdateaccumulator >= m_primaryupdaterate ) while( ( m_primaryupdateaccumulator >= m_primaryupdaterate )
&&( updatecount < 20 ) ) { &&( updatecount < 20 ) ) {
// no more than 20 updates per single pass, to keep physics from hogging up all run time // no more than 20 updates per single pass, to keep physics from hogging up all run time
Ground.Update( m_primaryupdaterate, 1 ); Ground.Update( m_primaryupdaterate, 1 );
++updatecount; ++updatecount;
m_primaryupdateaccumulator -= m_primaryupdaterate; 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
// this means at count > 20 simulation and render are going to desync. is that right?
// NOTE: experimentally changing this to prevent the desync.
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
Timer::subsystem.sim_dynamics.start();
if( true == Global.FullPhysics ) {
// mixed calculation mode, steps calculated in ~0.05s chunks
while( updatecount >= 5 ) {
simulation::State.update( stepdeltatime, 5 );
updatecount -= 5;
}
if( updatecount ) {
simulation::State.update( stepdeltatime, updatecount );
}
}
else {
// simplified calculation mode; faster but can lead to errors
simulation::State.update( stepdeltatime, updatecount );
}
Timer::subsystem.sim_dynamics.stop();
// secondary fixed step simulation time routines
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
// awaria PoKeys mogła włączyć pauzę - przekazać informację
if( Global.iMultiplayer ) // dajemy znać do serwera o wykonaniu
if( iPause != Global.iPause ) { // przesłanie informacji o pauzie do programu nadzorującego
multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania
iPause = Global.iPause;
}
// TODO: generic shake update pass for vehicles within view range
if( Camera.m_owner != nullptr ) {
Camera.m_owner->update_shake( m_secondaryupdaterate );
}
m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap
}
// variable step simulation time routines
if (!change_train.empty()) {
TTrain *train = simulation::Trains.find(change_train);
if (train) {
simulation::Train = train;
InOutKey();
m_relay.post(user_command::aidriverdisable, 0.0, 0.0, GLFW_PRESS, 0);
change_train.clear();
} }
*/
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
// this means at count > 20 simulation and render are going to desync. is that right?
// NOTE: experimentally changing this to prevent the desync.
// TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps
Timer::subsystem.sim_dynamics.start();
if( true == Global.FullPhysics ) {
// mixed calculation mode, steps calculated in ~0.05s chunks
while( updatecount >= 5 ) {
simulation::State.update( stepdeltatime, 5 );
updatecount -= 5;
}
if( updatecount ) {
simulation::State.update( stepdeltatime, updatecount );
}
}
else {
// simplified calculation mode; faster but can lead to errors
simulation::State.update( stepdeltatime, updatecount );
}
Timer::subsystem.sim_dynamics.stop();
// secondary fixed step simulation time routines
while( m_secondaryupdateaccumulator >= m_secondaryupdaterate ) {
// awaria PoKeys mogła włączyć pauzę - przekazać informację
if( Global.iMultiplayer ) // dajemy znać do serwera o wykonaniu
if( iPause != Global.iPause ) { // przesłanie informacji o pauzie do programu nadzorującego
multiplayer::WyslijParam( 5, 3 ); // ramka 5 z czasem i stanem zapauzowania
iPause = Global.iPause;
}
// TODO: generic shake update pass for vehicles within view range
if( Camera.m_owner != nullptr ) {
Camera.m_owner->update_shake( m_secondaryupdaterate );
}
m_secondaryupdateaccumulator -= m_secondaryupdaterate; // these should be inexpensive enough we have no cap
}
// variable step simulation time routines
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);
change_train.clear();
}
}
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
// intercept cases when the driven train got removed after entering portal
InOutKey();
}
if (!FreeFlyModeFlag && simulation::Train->Dynamic() != Camera.m_owner) {
// fixup camera after vehicle switch
CabView();
}
if( simulation::Train != nullptr )
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
else
TSubModel::iInstance = 0;
simulation::Trains.update(deltatime);
simulation::Events.update();
simulation::Region->update_events();
simulation::Lights.update();
} }
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
// intercept cases when the driven train got removed after entering portal
InOutKey();
}
if (!FreeFlyModeFlag && simulation::Train->Dynamic() != Camera.m_owner) {
// 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
TSubModel::iInstance = 0;
simulation::Trains.update(deltatime);
simulation::Events.update();
simulation::Region->update_events();
simulation::Lights.update();
// render time routines follow: // render time routines follow:
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
@@ -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 // NOTE: particle system runs on simulation time, but needs actual camera position to determine how to update each particle source
simulation::Particles.update(); simulation::Particles.update();
simulation::is_ready = true;
GfxRenderer->Update( deltarealtime ); GfxRenderer->Update( deltarealtime );
simulation::is_ready = simulation::is_ready || ( ( simulation::Train != nullptr ) && ( simulation::Train->is_cab_initialized ) ) || ( Global.local_start_vehicle == "ghostview" );
return true; return true;
} }
@@ -375,27 +366,24 @@ driver_mode::enter() {
simulation::Vehicles.find( Global.local_start_vehicle ) : simulation::Vehicles.find( Global.local_start_vehicle ) :
nullptr ) }; nullptr ) };
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nPlayerTrain ); Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr );
Global.pCamera = Camera; Global.pCamera = Camera;
Global.pDebugCamera = DebugCamera; Global.pDebugCamera = DebugCamera;
FreeFlyModeFlag = true;
DebugCamera = Camera;
if (nPlayerTrain) if (nPlayerTrain)
{ {
WriteLog( "Trying to enter player train, \"" + Global.local_start_vehicle + "\"" ); 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(), &Global.local_start_vehicle );
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0, nPlayerTrain->GetPosition());
change_train = nPlayerTrain->name(); change_train = nPlayerTrain->name();
} }
else else if (Global.local_start_vehicle != "ghostview")
{ {
if (Global.local_start_vehicle != "ghostview") Global.local_start_vehicle = "ghostview";
{ Error("Bad scenario: failed to locate player train, \"" + Global.local_start_vehicle + "\"" );
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 // if (!Global.bMultiplayer) //na razie włączone
@@ -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.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
Global.altState = ( Mods & GLFW_MOD_ALT ) ? 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... // 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 the input is left untouched, pass it on
if( true == m_input.keyboard.key( Key, Action ) ) { return; } 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; Camera.LookAt = controlled->GetPosition() + 0.4 * controlled->VectorUp() * controlled->MoverParameters->Dim.H;
} }
else { 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 ) 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 ) { if( d && pDynamicNearest ) {
// jeśli jakiś jest znaleziony wcześniej // jeśli jakiś jest znaleziony wcześniej
@@ -815,106 +805,32 @@ driver_mode::OnKeyDown(int cKey) {
} }
case GLFW_KEY_F5: { case GLFW_KEY_F5: {
// przesiadka do innego pojazdu // przesiadka do innego pojazdu
if (!FreeFlyModeFlag) if( !FreeFlyModeFlag ) { break; }
// only available in free fly mode
break;
TDynamicObject *dynamic = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) ); auto const *targetvehicle { std::get<TDynamicObject *>( simulation::Region->find_vehicle( Camera.Pos, 50, false, false ) ) };
if (dynamic) {
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0);
change_train = dynamic->name(); if( targetvehicle == nullptr ) { break; }
} if( ( targetvehicle->Mechanik ) &&
( false == targetvehicle->Mechanik->AIControllFlag ) ) {
break; // for the time being we don't allow more than one person per vehicle
/*
if( false == FreeFlyModeFlag ) {
// only available in free fly mode
break; break;
} }
TDynamicObject *targetvehicle = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) ); if( ( true == DebugModeFlag )
|| ( targetvehicle->MoverParameters->Vel <= 5.0 ) ) {
if( targetvehicle != nullptr ) { // works always in debug mode, or for stopped/slow moving vehicles otherwise
m_relay.post(
if( ( true == DebugModeFlag ) user_command::entervehicle,
|| ( targetvehicle->MoverParameters->Vel <= 5.0 ) ) { ( Global.ctrlState ? GLFW_MOD_CONTROL : 0 ), // TODO: remove ctrl key mode once manual cab (de)activation is in place,
// works always in debug mode, or for stopped/slow moving vehicles otherwise ( simulation::Train ? simulation::Train->id() : 0 ),
if( simulation::Train == nullptr ) { GLFW_PRESS,
simulation::Train = new TTrain(); // jeśli niczym jeszcze nie jeździlismy 0,
} targetvehicle->GetPosition(),
if( simulation::Train->Dynamic() != nullptr ) { &targetvehicle->name() );
// jeśli mielismy pojazd change_train = targetvehicle->name();
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ć
}
}
}
} }
break; break;
*/
} }
case GLFW_KEY_F6: { case GLFW_KEY_F6: {
// przyspieszenie symulacji do testowania scenerii... uwaga na FPS! // przyspieszenie symulacji do testowania scenerii... uwaga na FPS!
@@ -1176,67 +1092,6 @@ driver_mode::CabView() {
train->pMechOffset = Camera.m_owneroffset; 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 void
driver_mode::InOutKey() driver_mode::InOutKey()
{ // przełączenie widoku z kabiny na zewnętrzny i odwrotnie { // przełączenie widoku z kabiny na zewnętrzny i odwrotnie

View File

@@ -91,7 +91,6 @@ private:
void update_camera( const double Deltatime ); void update_camera( const double Deltatime );
// handles vehicle change flag // handles vehicle change flag
void OnKeyDown( int cKey ); void OnKeyDown( int cKey );
void ChangeDynamic();
void InOutKey(); void InOutKey();
void CabView(); void CabView();
void ExternalView(); 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 ) ) ) { if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
command_relay commandrelay; // NOTE: server shuts down entire network, client or standalone instance only shuts down self
commandrelay.post(user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0); if( Application.is_server() ) {
command_relay commandrelay;
commandrelay.post( user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0 );
}
else {
Application.queue_quit();
}
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "driveruipanels.h" #include "driveruipanels.h"
#include "Globals.h" #include "Globals.h"
#include "application.h"
#include "translation.h" #include "translation.h"
#include "simulation.h" #include "simulation.h"
#include "simulationtime.h" #include "simulationtime.h"
@@ -564,34 +565,45 @@ bool
debug_panel::render_section_scenario() { debug_panel::render_section_scenario() {
if( false == render_section( "Scenario", m_scenariolines ) ) { return false; } 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 // fog slider
{ {
auto fogrange = std::log( Global.fFogEnd ); auto fogrange = std::log( Global.fFogEnd );
if( ImGui::SliderFloat( 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" ) ) { ( 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 // cloud cover slider
{ {
if( ImGui::SliderFloat( if( ImGui::SliderFloat(
( to_string( Global.Overcast, 2, 5 ) + " (" + Global.Weather + ")###overcast" ).c_str(), &Global.Overcast, 0.0f, 2.0f, "Cloud cover" ) ) { ( 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 ); command_relay relay;
simulation::Environment.compute_weather(); relay.post(
user_command::setweather,
Global.fFogEnd,
clamp( Global.Overcast, 0.0f, 2.0f ),
GLFW_PRESS, 0 );
} }
} }
// day of year slider // 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" ) ) { if( ImGui::SliderFloat(
Global.fMoveLight = clamp( Global.fMoveLight, 0.0f, 365.0f ); ( to_string( Global.fMoveLight, 0, 5 ) + " (" + Global.Season + ")###movelight" ).c_str(), &Global.fMoveLight, 0.0f, 364.0f, "Day of year" ) ) {
auto const weather{ Global.Weather }; command_relay relay;
simulation::Environment.compute_season( Global.fMoveLight ); relay.post(
simulation::Time.init(); user_command::setdatetime,
if( weather != Global.Weather ) { clamp( Global.fMoveLight, 0.0f, 365.0f ),
// HACK: force re-calculation of precipitation simulation::Time.data().wHour * 60 + simulation::Time.data().wMinute,
Global.Overcast = clamp( Global.Overcast - 0.0001f, 0.0f, 2.0f ); GLFW_PRESS, 0 );
}
} }
} }
// time of day slider // 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 ) ) ) }; + 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" ) ) { if( ImGui::SliderInt( ( timestring + " (" + Global.Period + ")###simulationtime" ).c_str(), &time, 0, 1439, "Time of day" ) ) {
time = clamp( time, 0, 1439 ); command_relay relay;
auto const hour{ std::floor( time / 60 ) }; relay.post(
auto const minute{ time % 60 }; user_command::setdatetime,
simulation::Time.data().wHour = hour; Global.fMoveLight,
simulation::Time.data().wMinute = minute; clamp( time, 0, 1439 ),
GLFW_PRESS, 0 );
} }
} }
return true; 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_uint32(stream, seed);
sn_utils::ls_int64(stream, timestamp); 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) void network::server_hello::deserialize(std::istream &stream)
{ {
seed = sn_utils::ld_uint32(stream); seed = sn_utils::ld_uint32(stream);
timestamp = sn_utils::ld_int64(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 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.param2);
sn_utils::ls_float64(stream, data.time_delta); 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_vec3(stream, data.location);
sn_utils::s_str(stream, data.payload); 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.param2 = sn_utils::ld_float64(stream);
data.time_delta = 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.location = sn_utils::d_vec3(stream);
data.payload = sn_utils::d_str(stream); data.payload = sn_utils::d_str(stream);

View File

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

View File

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

View File

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

View File

@@ -36,7 +36,6 @@ scenarioloader_mode::init() {
// mode-specific update of simulation data. returns: false on error, true otherwise // mode-specific update of simulation data. returns: false on error, true otherwise
bool bool
scenarioloader_mode::update() { scenarioloader_mode::update() {
if (!Global.ready_to_load) if (!Global.ready_to_load)
// waiting for network connection // waiting for network connection
return true; return true;
@@ -44,7 +43,8 @@ scenarioloader_mode::update() {
if (!state) { if (!state) {
WriteLog("using simulation seed: " + std::to_string(Global.random_seed), logtype::generic); WriteLog("using simulation seed: " + std::to_string(Global.random_seed), logtype::generic);
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." ); Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" );
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." );
timestart = std::chrono::system_clock::now(); timestart = std::chrono::system_clock::now();
state = simulation::State.deserialize_begin(Global.SceneryFile); state = simulation::State.deserialize_begin(Global.SceneryFile);
@@ -63,7 +63,7 @@ scenarioloader_mode::update() {
// TODO: implement and use next mode cue // TODO: implement and use next mode cue
Application.pop_mode(); Application.pop_mode();
Application.push_mode( eu07_application::mode::driver ); Application.push_mode( eu07_application::mode::driver );
return true; return true;
} }
@@ -78,7 +78,7 @@ scenarioloader_mode::enter() {
simulation::is_ready = false; simulation::is_ready = false;
m_userinterface->set_background( "logo" ); 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();
m_userinterface->set_progress( "Loading scenery / Wczytywanie scenerii" ); m_userinterface->set_progress( "Loading scenery / Wczytywanie scenerii" );
GfxRenderer->Render(); GfxRenderer->Render();

View File

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

View File

@@ -218,28 +218,58 @@ void state_manager::process_commands() {
if (commanddata.command == user_command::entervehicle) { if (commanddata.command == user_command::entervehicle) {
// przesiadka do innego pojazdu // przesiadka do innego pojazdu
if (!commanddata.freefly) // NOTE: because malformed scenario can have vehicle name duplicates we first try to locate vehicle in world, with name search as fallback
// only available in free fly mode 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; 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 ) {
continue; // we already control desired vehicle so don't overcomplicate things
continue;
}
TTrain *train = simulation::Trains.find(dynamic->name()); auto const sameconsist{
if (train) ( targetvehicle->ctOwner == currentvehicle->Mechanik )
continue; || ( 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() ) };
if (train)
continue;
train = new TTrain(); train = new TTrain();
if (train->Init(dynamic)) { if (train->Init(targetvehicle)) {
simulation::Trains.insert(train); simulation::Trains.insert(train);
} }
else { else {
delete train; delete train;
train = nullptr; train = nullptr;
} }
}
}
if (commanddata.command == user_command::queueevent) { if (commanddata.command == user_command::queueevent) {
std::istringstream ss(commanddata.payload); std::istringstream ss(commanddata.payload);
@@ -268,11 +298,16 @@ void state_manager::process_commands() {
if (commanddata.command == user_command::setdatetime) { if (commanddata.command == user_command::setdatetime) {
int yearday = std::round(commanddata.param1); 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); simulation::Time.set_time(yearday, minute);
simulation::Environment.compute_season(yearday); 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) { if (commanddata.command == user_command::setweather) {
Global.fFogEnd = commanddata.param1; Global.fFogEnd = commanddata.param1;
@@ -394,6 +429,7 @@ void state_manager::process_commands() {
} }
if (commanddata.command == user_command::quitsimulation) { if (commanddata.command == user_command::quitsimulation) {
// TBD: allow clients to go into offline mode?
Application.queue_quit(); Application.queue_quit();
} }

View File

@@ -320,6 +320,9 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc
simulation::Events.InitLaunchers(); simulation::Events.InitLaunchers();
simulation::Memory.InitCells(); simulation::Memory.InitCells();
if (!Scratchpad.time_initialized)
init_time();
Scratchpad.initialized = true; Scratchpad.initialized = true;
} }
@@ -628,20 +631,14 @@ state_serializer::deserialize_time( cParser &Input, scene::scratch_data &Scratch
>> time.wHour >> time.wHour
>> time.wMinute; >> 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 // 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 // anything else left in the section has no defined meaning
skip_until( Input, "endtime" ); skip_until( Input, "endtime" );
if (!Scratchpad.time_initialized)
Scratchpad.time_initialized = true;
init_time();
} }
void void
@@ -974,6 +971,19 @@ state_serializer::deserialize_sound( cParser &Input, scene::scratch_data &Scratc
return sound; 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 // skips content of stream until specified token
void void
state_serializer::skip_until( cParser &Input, std::string const &Token ) { 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 ); 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 ); 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 ); 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 // skips content of stream until specified token
void skip_until( cParser &Input, std::string const &Token ); void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset // transforms provided location by specifed rotation and offset

View File

@@ -27,8 +27,10 @@ Copyright (C) 2007-2014 Maciej Cierniak
#include "Globals.h" #include "Globals.h"
#include "parser.h" #include "parser.h"
#include "Logs.h"
bool DebugModeFlag = false; bool DebugModeFlag = false;
bool FreeFlyModeFlag = true; bool FreeFlyModeFlag = false;
bool EditorModeFlag = false; bool EditorModeFlag = false;
bool DebugCameraFlag = false; bool DebugCameraFlag = false;
bool DebugTractionFlag = false; bool DebugTractionFlag = false;
@@ -107,7 +109,12 @@ bool ClearFlag( int &Flag, int const Value ) {
double Random(double a, double b) double Random(double a, double b)
{ {
uint32_t val = Global.random_engine(); uint32_t val = Global.random_engine();
return interpolate(a, b, (double)val / Global.random_engine.max()); #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());
} }
double LocalRandom(double a, double b) double LocalRandom(double a, double b)