16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 08:39:18 +02:00

network fixes and improvements, code refactoring

This commit is contained in:
milek7
2019-02-03 23:24:34 +01:00
parent 05ba7c653b
commit 85ad17af3c
29 changed files with 383 additions and 295 deletions

View File

@@ -74,4 +74,8 @@ enum class TCommandType
using material_handle = int; using material_handle = int;
using texture_handle = int; using texture_handle = int;
struct invalid_scenery_exception : std::runtime_error {
invalid_scenery_exception() : std::runtime_error("cannot load scenery") {}
};
#endif #endif

View File

@@ -1772,11 +1772,10 @@ void TController::Activation()
} }
if (pVehicle != old) if (pVehicle != old)
{ // jeśli zmieniony został pojazd prowadzony { // jeśli zmieniony został pojazd prowadzony
if( ( simulation::Train ) // ewentualna zmiana kabiny TTrain
&& ( simulation::Train->Dynamic() == old ) ) { TTrain *train = simulation::Trains.find(old->name());
// ewentualna zmiana kabiny użytkownikowi if (train)
Global.changeDynObj = pVehicle; // uruchomienie protezy train->MoveToVehicle(pVehicle);
}
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) -
// silnikowy dla EZT // silnikowy dla EZT
} }

View File

@@ -2330,17 +2330,6 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset )
if( Type == "" ) { return; } if( Type == "" ) { return; }
if( asName == Global.asHumanCtrlVehicle ) {
// 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" ) ) {

View File

@@ -52,7 +52,7 @@ global_settings::ConfigParse(cParser &Parser) {
{ {
Parser.getTokens(); Parser.getTokens();
Parser >> asHumanCtrlVehicle; Parser >> local_start_vehicle;
} }
else if( token == "fieldofview" ) { else if( token == "fieldofview" ) {

View File

@@ -30,7 +30,6 @@ struct global_settings {
std::mt19937 local_random_engine; std::mt19937 local_random_engine;
bool ready_to_load { false }; bool ready_to_load { false };
uint32_t random_seed; uint32_t random_seed;
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
@@ -61,7 +60,7 @@ struct global_settings {
std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS std::string szTexturesDDS{ ".dds" }; // lista tekstur od DDS
std::string szDefaultExt{ szTexturesDDS }; std::string szDefaultExt{ szTexturesDDS };
std::string SceneryFile{ "td.scn" }; std::string SceneryFile{ "td.scn" };
std::string asHumanCtrlVehicle{ "EU07-424" }; std::string local_start_vehicle{ "EU07-424" };
int iConvertModels{ 0 }; // tworzenie plików binarnych int iConvertModels{ 0 }; // tworzenie plików binarnych
// logs // logs
int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów

View File

@@ -46,12 +46,13 @@ std::string filename_date() {
std::snprintf( std::snprintf(
logbuffer, logbuffer,
sizeof(logbuffer), sizeof(logbuffer),
"%d%02d%02d_%02d%02d", "%d%02d%02d_%02d%02d%03d",
st.wYear, st.wYear,
st.wMonth, st.wMonth,
st.wDay, st.wDay,
st.wHour, st.wHour,
st.wMinute ); st.wMinute,
st.wMilliseconds);
return std::string( logbuffer ); return std::string( logbuffer );
} }

10
Names.h
View File

@@ -46,8 +46,16 @@ public:
auto lookup = m_itemmap.find( Name ); auto lookup = m_itemmap.find( Name );
if (lookup == m_itemmap.end()) if (lookup == m_itemmap.end())
return; return;
delete m_items[lookup->second]; delete m_items[lookup->second];
detach(Name);
}
void detach (std::string const &Name)
{
auto lookup = m_itemmap.find( Name );
if (lookup == m_itemmap.end())
return;
m_items[lookup->second] = nullptr; m_items[lookup->second] = nullptr;
// TBD, TODO: remove from m_items? // TBD, TODO: remove from m_items?

View File

@@ -4749,11 +4749,12 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm
if( false == Train->CabChange( 1 ) ) { if( false == Train->CabChange( 1 ) ) {
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::front ].CouplingFlag, coupling::gangway ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::front ].CouplingFlag, coupling::gangway ) ) {
// przejscie do nastepnego pojazdu // przejscie do nastepnego pojazdu
Global.changeDynObj = Train->DynamicObject->PrevConnected; TDynamicObject *dynobj = Train->DynamicObject->PrevConnected;
Global.changeDynObj->MoverParameters->ActiveCab = ( dynobj->MoverParameters->ActiveCab = (
Train->DynamicObject->PrevConnectedNo ? Train->DynamicObject->PrevConnectedNo ?
-1 : -1 :
1 ); 1 );
Train->MoveToVehicle(dynobj);
} }
} }
} }
@@ -4765,11 +4766,12 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com
if( false == Train->CabChange( -1 ) ) { if( false == Train->CabChange( -1 ) ) {
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::rear ].CouplingFlag, coupling::gangway ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::rear ].CouplingFlag, coupling::gangway ) ) {
// przejscie do nastepnego pojazdu // przejscie do nastepnego pojazdu
Global.changeDynObj = Train->DynamicObject->NextConnected; TDynamicObject *dynobj = Train->DynamicObject->NextConnected;
Global.changeDynObj->MoverParameters->ActiveCab = ( dynobj->MoverParameters->ActiveCab = (
Train->DynamicObject->NextConnectedNo ? Train->DynamicObject->NextConnectedNo ?
-1 : -1 :
1 ); 1 );
Train->MoveToVehicle(dynobj);
} }
} }
} }
@@ -6911,6 +6913,58 @@ void TTrain::DynamicSet(TDynamicObject *d)
} }
}; };
void
TTrain::MoveToVehicle(TDynamicObject *target) {
ErrorLog("MoveToVehicle");
// > Ra: to nie może być tak robione, to zbytnia proteza jest
// indeed, too much hacks...
simulation::Trains.detach(Dynamic()->name());
if( Dynamic()->Mechanik ) {
// AI może sobie samo pójść
if( false == Dynamic()->Mechanik->AIControllFlag ) {
// tylko jeśli ręcznie prowadzony
// jeśli prowadzi AI, to mu nie robimy dywersji!
Occupied()->CabDeactivisation();
Occupied()->ActiveCab = 0;
Occupied()->BrakeLevelSet( Occupied()->Handle->GetPos( bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016
Dynamic()->MechInside = false;
Dynamic()->Controller = AIdriver;
}
}
Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} );
if( Dynamic()->Mechanik ) // AI może sobie samo pójść
if( false == Dynamic()->Mechanik->AIControllFlag ) {
// tylko jeśli ręcznie prowadzony
// przsunięcie obiektu zarządzającego
Dynamic()->Mechanik->MoveTo( target );
}
DynamicSet( target );
if( Dynamic()->Mechanik ) // AI może sobie samo pójść
if( false == Dynamic()->Mechanik->AIControllFlag ) // tylko jeśli ręcznie prowadzony
{
Occupied()->LimPipePress = Occupied()->PipePress;
Occupied()->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
Dynamic()->MechInside = true;
Dynamic()->Controller = Humandriver;
}
InitializeCab(
Occupied()->CabNo,
Dynamic()->asBaseDir + Occupied()->TypeName + ".mmd" );
if( false == FreeFlyModeFlag ) {
Dynamic()->bDisplayCab = true;
Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem?
}
simulation::Trains.insert(this, Dynamic()->name());
}
// checks whether specified point is within boundaries of the active cab // checks whether specified point is within boundaries of the active cab
bool bool
TTrain::point_inside( Math3D::vector3 const Point ) const { TTrain::point_inside( Math3D::vector3 const Point ) const {

View File

@@ -670,6 +670,7 @@ private:
inline TMoverParameters *Occupied() { return mvOccupied; }; inline TMoverParameters *Occupied() { return mvOccupied; };
inline TMoverParameters const *Occupied() const { return mvOccupied; }; inline TMoverParameters const *Occupied() const { return mvOccupied; };
void DynamicSet(TDynamicObject *d); void DynamicSet(TDynamicObject *d);
void MoveToVehicle(TDynamicObject *target);
// checks whether specified point is within boundaries of the active cab // checks whether specified point is within boundaries of the active cab
bool point_inside( Math3D::vector3 const Point ) const; bool point_inside( Math3D::vector3 const Point ) const;
Math3D::vector3 clamp_inside( Math3D::vector3 const &Point ) const; Math3D::vector3 clamp_inside( Math3D::vector3 const &Point ) const;

View File

@@ -9,9 +9,9 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h" #include "stdafx.h"
#include "application.h" #include "application.h"
#include "scenarioloadermode.h"
#include "drivermode.h" #include "drivermode.h"
#include "editormode.h" #include "editormode.h"
#include "scenarioloadermode.h"
#include "Globals.h" #include "Globals.h"
#include "simulation.h" #include "simulation.h"
@@ -104,20 +104,20 @@ eu07_application::init( int Argc, char *Argv[] ) {
int result { 0 }; int result { 0 };
WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
WriteLog( "For online documentation and additional files refer to: http://eu07.pl" );
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
init_debug(); init_debug();
init_files(); init_files();
if( ( result = init_settings( Argc, Argv ) ) != 0 ) { if( ( result = init_settings( Argc, Argv ) ) != 0 ) {
return result; return result;
} }
WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
WriteLog( "For online documentation and additional files refer to: http://eu07.pl" );
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
if( ( result = init_locale() ) != 0 ) { if( ( result = init_locale() ) != 0 ) {
return result; return result;
} }
if( ( result = init_glfw() ) != 0 ) { if( ( result = init_glfw() ) != 0 ) {
return result; return result;
} }
@@ -171,81 +171,94 @@ eu07_application::run() {
double frameStartTime = Timer::GetTime(); double frameStartTime = Timer::GetTime();
bool nextloop = true; if (m_modes[m_modestack.top()]->is_command_processor()) {
while (nextloop) // active mode is doing real calculations (e.g. drivermode)
{
command_queue::commands_map commands_to_exec;
command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
double slave_sync;
// if we're the server bool nextloop = true;
if (m_network && m_network->servers) while (nextloop)
{ {
// fetch from network layer command requests received from clients command_queue::commands_map commands_to_exec;
command_queue::commands_map remote_commands = m_network->servers->pop_commands(); command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
double slave_sync;
// push these into local queue // if we're the server
add_to_dequemap(local_commands, remote_commands); if (m_network && m_network->servers)
} {
// fetch from network layer command requests received from clients
command_queue::commands_map remote_commands = m_network->servers->pop_commands();
// if we're slave // push these into local queue
if (m_network && m_network->client) add_to_dequemap(local_commands, remote_commands);
{ }
// fetch frame info from network layer,
auto frame_info = m_network->client->get_next_delta();
// use delta and commands received from master // if we're slave
double delta = std::get<0>(frame_info); if (m_network && m_network->client)
Timer::set_delta_override(delta); {
slave_sync = std::get<1>(frame_info); // fetch frame info from network layer,
add_to_dequemap(commands_to_exec, std::get<2>(frame_info)); auto frame_info = m_network->client->get_next_delta();
// and send our local commands to master // use delta and commands received from master
m_network->client->send_commands(local_commands); double delta = std::get<0>(frame_info);
Timer::set_delta_override(delta);
slave_sync = std::get<1>(frame_info);
add_to_dequemap(commands_to_exec, std::get<2>(frame_info));
// and send our local commands to master
m_network->client->send_commands(local_commands);
if (delta == 0.0)
nextloop = false;
}
// if we're master
else {
// just push local commands to execution
add_to_dequemap(commands_to_exec, local_commands);
if (delta == 0.0)
nextloop = false; nextloop = false;
} }
// if we're master
else {
// just push local commands to execution
add_to_dequemap(commands_to_exec, local_commands);
nextloop = false; // send commands to command queue
} simulation::Commands.push_commands(commands_to_exec);
// send commands to command queue // do actual frame processing
simulation::Commands.push_commands(commands_to_exec); if (!m_modes[ m_modestack.top() ]->update())
goto die;
// update continuous commands
simulation::Commands.update();
double sync = generate_sync();
// if we're the server
if (m_network && m_network->servers)
{
// send delta, sync, and commands we just executed to clients
double delta = Timer::GetDeltaTime();
m_network->servers->push_delta(delta, sync, commands_to_exec);
}
// if we're slave
if (m_network && m_network->client)
{
// verify sync
if (sync != slave_sync) {
WriteLog("net: DESYNC!", logtype::net);
}
// set total delta for rendering code
double totalDelta = Timer::GetTime() - frameStartTime;
Timer::set_delta_override(totalDelta);
}
}
} else {
// active mode is loader
// clear local command queue
simulation::Commands.pop_intercept_queue();
// do actual frame processing // do actual frame processing
if (!m_modes[ m_modestack.top() ]->update()) if (!m_modes[ m_modestack.top() ]->update())
goto die; goto die;
// update continuous commands
simulation::Commands.update();
double sync = generate_sync();
// if we're the server
if (m_network && m_network->servers)
{
// send delta, sync, and commands we just executed to clients
double delta = Timer::GetDeltaTime();
m_network->servers->push_delta(delta, sync, commands_to_exec);
}
// if we're slave
if (m_network && m_network->client)
{
// verify sync
if (sync != slave_sync) {
WriteLog("net: DESYNC!", logtype::net);
}
// set total delta for rendering code
double totalDelta = Timer::GetTime() - frameStartTime;
Timer::set_delta_override(totalDelta);
}
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@@ -269,7 +282,7 @@ eu07_application::run() {
} }
if (m_network) if (m_network)
m_network->poll(); m_network->update();
auto frametime = Timer::subsystem.mainloop_total.stop(); auto frametime = Timer::subsystem.mainloop_total.stop();
if (Global.minframetime.count() != 0.0f && (Global.minframetime - frametime).count() > 0.0f) if (Global.minframetime.count() != 0.0f && (Global.minframetime - frametime).count() > 0.0f)
@@ -490,7 +503,7 @@ eu07_application::init_files() {
#elif __linux__ #elif __linux__
unlink("log.txt"); unlink("log.txt");
unlink("errors.txt"); unlink("errors.txt");
mkdir("logs", 0664); mkdir("logs", 0755);
#endif #endif
} }
@@ -519,7 +532,7 @@ eu07_application::init_settings( int Argc, char *Argv[] ) {
} }
else if( token == "-v" ) { else if( token == "-v" ) {
if( i + 1 < Argc ) { if( i + 1 < Argc ) {
Global.asHumanCtrlVehicle = ToLower( Argv[ ++i ] ); Global.local_start_vehicle = ToLower( Argv[ ++i ] );
} }
} }
else { else {
@@ -709,6 +722,11 @@ bool eu07_application::init_network() {
if (Global.network_conf.is_client) { if (Global.network_conf.is_client) {
m_network->connect(Global.network_conf.client_host, Global.network_conf.client_port); m_network->connect(Global.network_conf.client_host, Global.network_conf.client_port);
} }
else {
Global.random_seed = std::random_device{}();
Global.random_engine.seed(Global.random_seed);
Global.ready_to_load = true;
}
} }
return true; return true;

View File

@@ -63,6 +63,9 @@ public:
virtual virtual
void void
on_event_poll() = 0; on_event_poll() = 0;
virtual
bool
is_command_processor() = 0;
protected: protected:
// members // members

View File

@@ -197,9 +197,9 @@ driver_mode::update() {
InOutKey(); InOutKey();
} }
if( Global.changeDynObj ) { if (!FreeFlyModeFlag && simulation::Train->Dynamic() != Camera.m_owner) {
// ABu zmiana pojazdu - przejście do innego // fixup camera after vehicle switch
ChangeDynamic(); CabView();
} }
if( simulation::Train != nullptr ) if( simulation::Train != nullptr )
@@ -264,8 +264,8 @@ void
driver_mode::enter() { driver_mode::enter() {
TDynamicObject *nPlayerTrain { ( TDynamicObject *nPlayerTrain { (
( Global.asHumanCtrlVehicle != "ghostview" ) ? ( Global.local_start_vehicle != "ghostview" ) ?
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : simulation::Vehicles.find( Global.local_start_vehicle ) :
nullptr ) }; nullptr ) };
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr ); Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr );
@@ -277,14 +277,14 @@ driver_mode::enter() {
if (nPlayerTrain) if (nPlayerTrain)
{ {
WriteLog( "Trying to enter player train, \"" + Global.asHumanCtrlVehicle + "\"" ); WriteLog( "Trying to enter player train, \"" + Global.local_start_vehicle + "\"" );
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());
change_train = nPlayerTrain->name(); change_train = nPlayerTrain->name();
} }
else if (Global.asHumanCtrlVehicle != "ghostview") else if (Global.local_start_vehicle != "ghostview")
{ {
Error("Bad scenario: failed to locate player train, \"" + Global.asHumanCtrlVehicle + "\"" ); Error("Bad scenario: failed to locate player train, \"" + Global.local_start_vehicle + "\"" );
} }
// if (!Global.bMultiplayer) //na razie włączone // if (!Global.bMultiplayer) //na razie włączone
@@ -301,7 +301,7 @@ driver_mode::enter() {
KeyEvents[ 9 ] = simulation::Events.FindEvent( "keyctrl09" ); KeyEvents[ 9 ] = simulation::Events.FindEvent( "keyctrl09" );
} }
Timer::ResetTimers(); Timer::ResetTimers();
set_picking( Global.ControlPicking ); set_picking( Global.ControlPicking );
} }
@@ -377,6 +377,12 @@ driver_mode::on_event_poll() {
m_input.poll(); m_input.poll();
} }
bool
driver_mode::is_command_processor() {
return true;
}
void void
driver_mode::update_camera( double const Deltatime ) { driver_mode::update_camera( double const Deltatime ) {
@@ -946,65 +952,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->ActiveCab = 0;
occupied->BrakeLevelSet( occupied->Handle->GetPos( bh_NP ) ); //rozwala sterowanie hamulcem GF 04-2016
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.asHumanCtrlVehicle = 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(); // załączenie rozrządu (wirtualne kabiny)
vehicle->MechInside = true;
vehicle->Controller = Humandriver;
}
train->InitializeCab(
occupied->CabNo,
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

@@ -49,6 +49,8 @@ public:
on_scroll( double const Xoffset, double const Yoffset ) override; on_scroll( double const Xoffset, double const Yoffset ) override;
void void
on_event_poll() override; on_event_poll() override;
bool
is_command_processor() override;
private: private:
// types // types
@@ -86,7 +88,7 @@ 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();
@@ -99,7 +101,7 @@ private:
TCamera Camera; TCamera Camera;
TCamera DebugCamera; TCamera DebugCamera;
int m_externalviewmode { view::consistfront }; // selected external view mode int m_externalviewmode { view::consistfront }; // selected external view mode
bool m_externalview { false }; bool m_externalview { true };
std::array<view_config, view::count_> m_externalviewconfigs; std::array<view_config, view::count_> m_externalviewconfigs;
TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys

View File

@@ -262,6 +262,11 @@ editor_mode::on_event_poll() {
m_input.poll(); m_input.poll();
} }
bool editor_mode::is_command_processor() {
return false;
}
bool bool
editor_mode::mode_translation() const { editor_mode::mode_translation() const {

View File

@@ -45,6 +45,8 @@ public:
on_scroll( double const Xoffset, double const Yoffset ) override { ; } on_scroll( double const Xoffset, double const Yoffset ) override { ; }
void void
on_event_poll() override; on_event_poll() override;
bool
is_command_processor() override;
private: private:
// types // types

View File

@@ -140,7 +140,7 @@ OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
// jeśli długość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7 // jeśli długość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7
auto *vehicle = ( auto *vehicle = (
pRozkaz->cString[ 1 ] == '*' ? pRozkaz->cString[ 1 ] == '*' ?
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : simulation::Train->Dynamic() :
simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) ); simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) );
if( vehicle != nullptr ) { if( vehicle != nullptr ) {
WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe
@@ -181,7 +181,7 @@ OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13 { // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13
auto *lookup = ( auto *lookup = (
pRozkaz->cString[ 2 ] == '*' ? pRozkaz->cString[ 2 ] == '*' ?
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) : // nazwa pojazdu użytkownika simulation::Train->Dynamic() : // nazwa pojazdu użytkownika
simulation::Vehicles.find( std::string( pRozkaz->cString + 2, (unsigned)pRozkaz->cString[ 1 ] ) ) ); // nazwa pojazdu simulation::Vehicles.find( std::string( pRozkaz->cString + 2, (unsigned)pRozkaz->cString[ 1 ] ) ) ); // nazwa pojazdu
if( lookup == nullptr ) { break; } // nothing found, nothing to do if( lookup == nullptr ) { break; } // nothing found, nothing to do
auto *d { lookup }; auto *d { lookup };

View File

@@ -9,10 +9,14 @@ network::tcp::connection::connection(asio::io_context &io_ctx, bool client, size
m_header_buffer.resize(8); m_header_buffer.resize(8);
} }
network::tcp::connection::~connection()
{
m_socket.close();
}
void network::tcp::connection::disconnect() void network::tcp::connection::disconnect()
{ {
network::connection::disconnect(); network::connection::disconnect();
m_socket.close();
} }
void network::tcp::connection::send_data(std::shared_ptr<std::string> buffer) void network::tcp::connection::send_data(std::shared_ptr<std::string> buffer)
@@ -176,8 +180,6 @@ void network::tcp::client::connect()
if (this->conn) if (this->conn)
return; return;
std::cout << "create sock" << std::endl;
std::shared_ptr<connection> conn = std::make_shared<connection>(io_ctx, true, resume_frame_counter); std::shared_ptr<connection> conn = std::make_shared<connection>(io_ctx, true, resume_frame_counter);
conn->set_handler(std::bind(&client::handle_message, this, conn, std::placeholders::_1)); conn->set_handler(std::bind(&client::handle_message, this, conn, std::placeholders::_1));
@@ -187,7 +189,6 @@ void network::tcp::client::connect()
conn->m_socket.set_option(asio::ip::tcp::no_delay(true)); conn->m_socket.set_option(asio::ip::tcp::no_delay(true));
conn->m_socket.async_connect(endpoint, conn->m_socket.async_connect(endpoint,
std::bind(&client::handle_accept, this, std::placeholders::_1)); std::bind(&client::handle_accept, this, std::placeholders::_1));
std::cout << "connect start" <<std::endl;
this->conn = conn; this->conn = conn;
@@ -195,7 +196,6 @@ void network::tcp::client::connect()
void network::tcp::client::handle_accept(const asio::error_code &err) void network::tcp::client::handle_accept(const asio::error_code &err)
{ {
std::cout << "connect handl" <<std::endl;
if (!err) if (!err)
{ {
conn->connected(); conn->connected();
@@ -203,6 +203,6 @@ void network::tcp::client::handle_accept(const asio::error_code &err)
else else
{ {
WriteLog(std::string("net: failed to connect: " + err.message()), logtype::net); WriteLog(std::string("net: failed to connect: " + err.message()), logtype::net);
conn->state = connection::DEAD; conn->disconnect();
} }
} }

View File

@@ -14,6 +14,7 @@ namespace network::tcp
public: public:
connection(asio::io_context &io_ctx, bool client = false, size_t counter = 0); connection(asio::io_context &io_ctx, bool client = false, size_t counter = 0);
~connection();
virtual void connected() override; virtual void connected() override;
virtual void disconnect() override; virtual void disconnect() override;

View File

@@ -22,14 +22,14 @@ void network::server_manager::push_delta(double dt, double sync, const command_q
if (dt == 0.0 && commands.empty()) if (dt == 0.0 && commands.empty())
return; return;
for (auto srv : servers)
srv->push_delta(dt, sync, commands);
frame_info msg; frame_info msg;
msg.dt = dt; msg.dt = dt;
msg.sync = sync; msg.sync = sync;
msg.commands = commands; msg.commands = commands;
for (auto srv : servers)
srv->push_delta(msg);
serialize_message(msg, *backbuffer.get()); serialize_message(msg, *backbuffer.get());
} }
@@ -42,10 +42,13 @@ network::manager::manager()
{ {
} }
void network::manager::poll() void network::manager::update()
{ {
io_context.restart(); io_context.restart();
io_context.poll(); io_context.poll();
if (client)
client->update();
} }
void network::manager::create_server(const std::string &host, uint32_t port) void network::manager::create_server(const std::string &host, uint32_t port)

View File

@@ -32,6 +32,6 @@ namespace network
void create_server(const std::string &host, uint32_t port); void create_server(const std::string &host, uint32_t port);
void connect(const std::string &host, uint32_t port); void connect(const std::string &host, uint32_t port);
void poll(); void update();
}; };
} }

View File

@@ -40,27 +40,29 @@ void network::connection::catch_up()
std::vector<std::shared_ptr<message>> messages; std::vector<std::shared_ptr<message>> messages;
for (size_t i = 0; i < CATCHUP_PACKETS; i++) { for (int i = 0; i < CATCHUP_PACKETS; i++) {
if (backbuffer->peek() == EOF) { if (backbuffer->peek() == EOF) {
send_messages(messages); send_messages(messages);
backbuffer->seekg(0, std::ios_base::end);
state = ACTIVE; state = ACTIVE;
backbuffer->seekg(0, std::ios_base::end);
return; return;
} }
auto msg = deserialize_message(*backbuffer.get());
if (packet_counter) { if (packet_counter) {
packet_counter--; packet_counter--;
i--; // TODO: it would be better to skip frames in chunks
continue; continue;
} }
messages.push_back(deserialize_message(*backbuffer.get())); messages.push_back(msg);
} }
send_messages(messages);
backbuffer_pos = backbuffer->tellg(); backbuffer_pos = backbuffer->tellg();
backbuffer->seekg(0, std::ios_base::end); backbuffer->seekg(0, std::ios_base::end);
send_messages(messages);
} }
void network::connection::send_complete(std::shared_ptr<std::string> buf) void network::connection::send_complete(std::shared_ptr<std::string> buf)
@@ -108,13 +110,8 @@ network::server::server(std::shared_ptr<std::istream> buf) : backbuffer(buf)
} }
void network::server::push_delta(double dt, double sync, const command_queue::commands_map &commands) void network::server::push_delta(const frame_info &msg)
{ {
frame_info msg;
msg.dt = dt;
msg.sync = sync;
msg.commands = commands;
for (auto it = clients.begin(); it != clients.end(); ) { for (auto it = clients.begin(); it != clients.end(); ) {
if ((*it)->state == connection::DEAD) { if ((*it)->state == connection::DEAD) {
it = clients.erase(it); it = clients.erase(it);
@@ -146,6 +143,11 @@ 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) {
conn->disconnect();
return;
}
server_hello reply; server_hello reply;
reply.seed = Global.random_seed; reply.seed = Global.random_seed;
conn->state = connection::CATCHING_UP; conn->state = connection::CATCHING_UP;
@@ -167,20 +169,24 @@ void network::server::handle_message(std::shared_ptr<connection> conn, const mes
// ------------ // ------------
// client void network::client::update()
int zzz = 20;
std::tuple<double, double, command_queue::commands_map> network::client::get_next_delta()
{ {
if (conn && conn->state == connection::DEAD) { if (conn && conn->state == connection::DEAD) {
conn.reset(); conn.reset();
} }
if (!conn) { if (!conn) {
zzz--; if (!reconnect_delay) {
if (zzz < 0)
connect(); connect();
reconnect_delay = RECONNECT_DELAY_FRAMES;
}
reconnect_delay--;
} }
}
// client
std::tuple<double, double, command_queue::commands_map> network::client::get_next_delta()
{
if (delta_queue.empty()) { if (delta_queue.empty()) {
return std::tuple<double, double, return std::tuple<double, double,
command_queue::commands_map>(0.0, 0.0, command_queue::commands_map()); command_queue::commands_map>(0.0, 0.0, command_queue::commands_map());
@@ -189,6 +195,7 @@ std::tuple<double, double, command_queue::commands_map> network::client::get_nex
auto entry = delta_queue.front(); auto entry = delta_queue.front();
delta_queue.pop(); delta_queue.pop();
auto &delta = entry.second;
return std::make_tuple(entry.second.dt, entry.second.sync, entry.second.commands); return std::make_tuple(entry.second.dt, entry.second.sync, entry.second.commands);
} }
@@ -216,9 +223,11 @@ void network::client::handle_message(std::shared_ptr<connection> conn, const mes
auto cmd = dynamic_cast<const server_hello&>(msg); auto cmd = dynamic_cast<const server_hello&>(msg);
conn->state = connection::ACTIVE; conn->state = connection::ACTIVE;
Global.random_seed = cmd.seed; if (!Global.ready_to_load) {
Global.random_engine.seed(Global.random_seed); Global.random_seed = cmd.seed;
Global.ready_to_load = true; Global.random_engine.seed(Global.random_seed);
Global.ready_to_load = true;
}
WriteLog("net: accept received", logtype::net); WriteLog("net: accept received", logtype::net);
} }

View File

@@ -16,7 +16,7 @@ namespace network
friend class client; friend class client;
private: private:
const size_t CATCHUP_PACKETS = 100; const int CATCHUP_PACKETS = 100;
/* /*
std::queue< std::queue<
@@ -74,7 +74,7 @@ namespace network
public: public:
server(std::shared_ptr<std::istream> buf); server(std::shared_ptr<std::istream> buf);
void push_delta(double dt, double sync, const command_queue::commands_map &commands); void push_delta(const frame_info &msg);
command_queue::commands_map pop_commands(); command_queue::commands_map pop_commands();
}; };
@@ -85,12 +85,16 @@ namespace network
void handle_message(std::shared_ptr<connection> conn, const message &msg); void handle_message(std::shared_ptr<connection> conn, const message &msg);
std::shared_ptr<connection> conn; std::shared_ptr<connection> conn;
size_t resume_frame_counter = 0; size_t resume_frame_counter = 0;
size_t reconnect_delay = 0;
const size_t RECONNECT_DELAY_FRAMES = 60;
std::queue< std::queue<
std::pair<std::chrono::high_resolution_clock::time_point, std::pair<std::chrono::high_resolution_clock::time_point,
frame_info>> delta_queue; frame_info>> delta_queue;
public: public:
void update();
std::tuple<double, double, command_queue::commands_map> get_next_delta(); std::tuple<double, double, command_queue::commands_map> get_next_delta();
void send_commands(command_queue::commands_map commands); void send_commands(command_queue::commands_map commands);
}; };

View File

@@ -2114,9 +2114,6 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
m_sunlight.apply_intensity(Dynamic->fShade); m_sunlight.apply_intensity(Dynamic->fShade);
} }
// calc_motion = true;
// std::cout << glm::to_string(glm::vec3(Dynamic->get_velocity_vec())) << std::endl;
// render // render
if (Dynamic->mdLowPolyInt) if (Dynamic->mdLowPolyInt)
Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance); Render(Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance);
@@ -2128,7 +2125,6 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
Render(Dynamic->mdLoad, Dynamic->Material(), squaredistance, {0.f, Dynamic->LoadOffset, 0.f}, {}); Render(Dynamic->mdLoad, Dynamic->Material(), squaredistance, {0.f, Dynamic->LoadOffset, 0.f}, {});
// post-render cleanup // post-render cleanup
// calc_motion = false;
if (Dynamic->fShade > 0.0f) if (Dynamic->fShade > 0.0f)
{ {

View File

@@ -35,27 +35,40 @@ 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)
// waiting for network connection
return true;
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." ); if (!state) {
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." );
auto timestart = std::chrono::system_clock::now(); timestart = std::chrono::system_clock::now();
state = simulation::State.deserialize_begin(Global.SceneryFile);
}
if( true == simulation::State.deserialize( Global.SceneryFile ) ) { try {
WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" ); if (simulation::State.deserialize_continue(state))
// TODO: implement and use next mode cue return true;
Global.random_seed = std::random_device{}(); }
Global.random_engine.seed(Global.random_seed); catch (invalid_scenery_exception &e) {
Application.pop_mode(); ErrorLog( "Bad init: scenario loading failed" );
Application.push_mode( eu07_application::mode::driver ); Application.pop_mode();
} }
else {
ErrorLog( "Bad init: scenario loading failed" ); WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" );
Application.pop_mode(); // TODO: implement and use next mode cue
}
Application.pop_mode();
Application.push_mode( eu07_application::mode::driver );
return true; return true;
} }
bool
scenarioloader_mode::is_command_processor() {
return false;
}
// maintenance method, called when the mode is activated // maintenance method, called when the mode is activated
void void
scenarioloader_mode::enter() { scenarioloader_mode::enter() {

View File

@@ -10,8 +10,11 @@ http://mozilla.org/MPL/2.0/.
#pragma once #pragma once
#include "applicationmode.h" #include "applicationmode.h"
#include "simulation.h"
class scenarioloader_mode : public application_mode { class scenarioloader_mode : public application_mode {
std::shared_ptr<simulation::deserializer_state> state;
std::chrono::system_clock::time_point timestart;
public: public:
// constructors // constructors
@@ -40,4 +43,6 @@ public:
on_scroll( double const Xoffset, double const Yoffset ) override { ; } on_scroll( double const Xoffset, double const Yoffset ) override { ; }
void void
on_event_poll() override { ; } on_event_poll() override { ; }
bool
is_command_processor() override;
}; };

View File

@@ -45,10 +45,16 @@ TTrain *Train { nullptr };
uint16_t prev_train_id { 0 }; uint16_t prev_train_id { 0 };
bool is_ready { false }; bool is_ready { false };
bool std::shared_ptr<deserializer_state>
state_manager::deserialize( std::string const &Scenariofile ) { state_manager::deserialize_begin(std::string const &Scenariofile) {
return m_serializer.deserialize( Scenariofile ); return m_serializer.deserialize_begin( Scenariofile );
}
bool
state_manager::deserialize_continue(std::shared_ptr<deserializer_state> state) {
return m_serializer.deserialize_continue(state);
} }
// stores class data in specified file, in legacy (text) format // stores class data in specified file, in legacy (text) format

View File

@@ -26,9 +26,12 @@ public:
update( double Deltatime, int Iterationcount ); update( double Deltatime, int Iterationcount );
void void
update_clocks(); update_clocks();
// restores simulation data from specified file. returns: true on success, false otherwise // starts deserialization from specified file, returns context pointer on success, throws otherwise
bool std::shared_ptr<deserializer_state>
deserialize( std::string const &Scenariofile ); deserialize_begin(std::string const &Scenariofile);
// continues deserialization for given context, amount limited by time, returns true if needs to be called again
bool
deserialize_continue(std::shared_ptr<deserializer_state> state);
// stores class data in specified file, in legacy (text) format // stores class data in specified file, in legacy (text) format
void void
export_as_text( std::string const &Scenariofile ) const; export_as_text( std::string const &Scenariofile ) const;
@@ -63,6 +66,8 @@ extern TTrain *Train;
extern uint16_t prev_train_id; extern uint16_t prev_train_id;
extern bool is_ready; extern bool is_ready;
class deserializer_state;
} // simulation } // simulation
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -25,98 +25,87 @@ http://mozilla.org/MPL/2.0/.
namespace simulation { namespace simulation {
bool std::shared_ptr<deserializer_state>
state_serializer::deserialize( std::string const &Scenariofile ) { state_serializer::deserialize_begin( std::string const &Scenariofile ) {
// TODO: move initialization to separate routine so we can reuse it // TODO: move initialization to separate routine so we can reuse it
SafeDelete( Region ); SafeDelete( Region );
Region = new scene::basic_region(); Region = new scene::basic_region();
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
std::shared_ptr<deserializer_state> state =
std::make_shared<deserializer_state>(Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction);
// TODO: check first for presence of serialized binary files // TODO: check first for presence of serialized binary files
// if this fails, fall back on the legacy text format // if this fails, fall back on the legacy text format
scene::scratch_data importscratchpad; state->scratchpad.name = Scenariofile;
importscratchpad.name = Scenariofile;
if( Scenariofile != "$.scn" ) { if( Scenariofile != "$.scn" ) {
// compilation to binary file isn't supported for rainsted-created overrides // compilation to binary file isn't supported for rainsted-created overrides
// NOTE: we postpone actual loading of the scene until we process time, season and weather data // NOTE: we postpone actual loading of the scene until we process time, season and weather data
importscratchpad.binary.terrain = Region->is_scene( Scenariofile ) ; state->scratchpad.binary.terrain = Region->is_scene( Scenariofile ) ;
} }
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global.asCurrentSceneryPath, Global.bLoadTraction );
if( false == scenarioparser.ok() ) { return false; } if( false == state->input.ok() )
throw invalid_scenery_exception();
deserialize( scenarioparser, importscratchpad ); // prepare deserialization function table
if( ( false == importscratchpad.binary.terrain ) // since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
&& ( Scenariofile != "$.scn" ) ) { using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &);
// if we didn't find usable binary version of the scenario files, create them now for future use std::vector<
// as long as the scenario file wasn't rainsted-created base file override std::pair<
Region->serialize( Scenariofile ); std::string,
} deserializefunction> > functionlist = {
return true; { "area", &state_serializer::deserialize_area },
{ "atmo", &state_serializer::deserialize_atmo },
{ "camera", &state_serializer::deserialize_camera },
{ "config", &state_serializer::deserialize_config },
{ "description", &state_serializer::deserialize_description },
{ "event", &state_serializer::deserialize_event },
{ "lua", &state_serializer::deserialize_lua },
{ "firstinit", &state_serializer::deserialize_firstinit },
{ "group", &state_serializer::deserialize_group },
{ "endgroup", &state_serializer::deserialize_endgroup },
{ "light", &state_serializer::deserialize_light },
{ "node", &state_serializer::deserialize_node },
{ "origin", &state_serializer::deserialize_origin },
{ "endorigin", &state_serializer::deserialize_endorigin },
{ "rotate", &state_serializer::deserialize_rotate },
{ "sky", &state_serializer::deserialize_sky },
{ "test", &state_serializer::deserialize_test },
{ "time", &state_serializer::deserialize_time },
{ "trainset", &state_serializer::deserialize_trainset },
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
for( auto &function : functionlist ) {
state->functionmap.emplace( function.first, std::bind( function.second, this, std::ref( state->input ), std::ref( state->scratchpad ) ) );
}
return state;
} }
// restores class data from provided stream // continues deserialization for given context, amount limited by time, returns true if needs to be called again
void bool
state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) { state_serializer::deserialize_continue(std::shared_ptr<deserializer_state> state) {
cParser &Input = state->input;
// prepare deserialization function table scene::scratch_data &Scratchpad = state->scratchpad;
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
using deserializefunction = void( state_serializer::*)(cParser &, scene::scratch_data &);
std::vector<
std::pair<
std::string,
deserializefunction> > functionlist = {
{ "area", &state_serializer::deserialize_area },
{ "atmo", &state_serializer::deserialize_atmo },
{ "camera", &state_serializer::deserialize_camera },
{ "config", &state_serializer::deserialize_config },
{ "description", &state_serializer::deserialize_description },
{ "event", &state_serializer::deserialize_event },
{ "lua", &state_serializer::deserialize_lua },
{ "firstinit", &state_serializer::deserialize_firstinit },
{ "group", &state_serializer::deserialize_group },
{ "endgroup", &state_serializer::deserialize_endgroup },
{ "light", &state_serializer::deserialize_light },
{ "node", &state_serializer::deserialize_node },
{ "origin", &state_serializer::deserialize_origin },
{ "endorigin", &state_serializer::deserialize_endorigin },
{ "rotate", &state_serializer::deserialize_rotate },
{ "sky", &state_serializer::deserialize_sky },
{ "test", &state_serializer::deserialize_test },
{ "time", &state_serializer::deserialize_time },
{ "trainset", &state_serializer::deserialize_trainset },
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
using deserializefunctionbind = std::function<void()>;
std::unordered_map<
std::string,
deserializefunctionbind> functionmap;
for( auto &function : functionlist ) {
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
}
// deserialize content from the provided input // deserialize content from the provided input
auto auto timelast { std::chrono::steady_clock::now() };
timelast { std::chrono::steady_clock::now() },
timenow { timelast };
std::string token { Input.getToken<std::string>() }; std::string token { Input.getToken<std::string>() };
while( false == token.empty() ) { while( false == token.empty() ) {
auto lookup = functionmap.find( token ); auto lookup = state->functionmap.find( token );
if( lookup != functionmap.end() ) { if( lookup != state->functionmap.end() ) {
lookup->second(); lookup->second();
} }
else { else {
ErrorLog( "Bad scenario: unexpected token \"" + token + "\" defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" ); ErrorLog( "Bad scenario: unexpected token \"" + token + "\" defined in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
} }
timenow = std::chrono::steady_clock::now(); auto timenow = std::chrono::steady_clock::now();
if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) { if( std::chrono::duration_cast<std::chrono::milliseconds>( timenow - timelast ).count() >= 200 ) {
timelast = timenow;
glfwPollEvents();
Application.set_progress( Input.getProgress(), Input.getFullProgress() ); Application.set_progress( Input.getProgress(), Input.getFullProgress() );
GfxRenderer.Render(); return true;
GfxRenderer.SwapBuffers();
} }
token = Input.getToken<std::string>(); token = Input.getToken<std::string>();
@@ -129,6 +118,15 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
if (Global.map_enabled) if (Global.map_enabled)
Region->create_map_geometry(); Region->create_map_geometry();
if( ( false == state->scratchpad.binary.terrain )
&& ( state->scenariofile != "$.scn" ) ) {
// if we didn't find usable binary version of the scenario files, create them now for future use
// as long as the scenario file wasn't rainsted-created base file override
Region->serialize( state->scenariofile );
}
return false;
} }
void void

View File

@@ -14,21 +14,37 @@ http://mozilla.org/MPL/2.0/.
namespace simulation { namespace simulation {
struct deserializer_state {
std::string scenariofile;
cParser input;
scene::scratch_data scratchpad;
using deserializefunctionbind = std::function<void()>;
std::unordered_map<
std::string,
deserializefunctionbind> functionmap;
deserializer_state(std::string const &File, cParser::buffertype const Type, const std::string &Path, bool const Loadtraction)
: scenariofile(File), input(File, Type, Path, Loadtraction) { }
};
class state_serializer { class state_serializer {
public: public:
// methods // methods
// restores simulation data from specified file. returns: true on success, false otherwise // starts deserialization from specified file, returns context pointer on success, throws otherwise
bool std::shared_ptr<deserializer_state>
deserialize( std::string const &Scenariofile ); deserialize_begin(std::string const &Scenariofile);
// continues deserialization for given context, amount limited by time, returns true if needs to be called again
bool
deserialize_continue(std::shared_ptr<deserializer_state> state);
// stores class data in specified file, in legacy (text) format // stores class data in specified file, in legacy (text) format
void void
export_as_text( std::string const &Scenariofile ) const; export_as_text( std::string const &Scenariofile ) const;
private: private:
// methods // methods
// restores class data from provided stream // restores class data from provided stream
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );