mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
network fixes and improvements, code refactoring
This commit is contained in:
@@ -74,4 +74,8 @@ enum class TCommandType
|
||||
using material_handle = int;
|
||||
using texture_handle = int;
|
||||
|
||||
struct invalid_scenery_exception : std::runtime_error {
|
||||
invalid_scenery_exception() : std::runtime_error("cannot load scenery") {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1772,11 +1772,10 @@ void TController::Activation()
|
||||
}
|
||||
if (pVehicle != old)
|
||||
{ // jeśli zmieniony został pojazd prowadzony
|
||||
if( ( simulation::Train )
|
||||
&& ( simulation::Train->Dynamic() == old ) ) {
|
||||
// ewentualna zmiana kabiny użytkownikowi
|
||||
Global.changeDynObj = pVehicle; // uruchomienie protezy
|
||||
}
|
||||
// ewentualna zmiana kabiny TTrain
|
||||
TTrain *train = simulation::Trains.find(old->name());
|
||||
if (train)
|
||||
train->MoveToVehicle(pVehicle);
|
||||
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) -
|
||||
// silnikowy dla EZT
|
||||
}
|
||||
|
||||
11
DynObj.cpp
11
DynObj.cpp
@@ -2330,17 +2330,6 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset )
|
||||
|
||||
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
|
||||
if( ( Type == "1" )
|
||||
|| ( Type == "2" ) ) {
|
||||
|
||||
@@ -52,7 +52,7 @@ global_settings::ConfigParse(cParser &Parser) {
|
||||
{
|
||||
|
||||
Parser.getTokens();
|
||||
Parser >> asHumanCtrlVehicle;
|
||||
Parser >> local_start_vehicle;
|
||||
}
|
||||
else if( token == "fieldofview" ) {
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ struct global_settings {
|
||||
std::mt19937 local_random_engine;
|
||||
bool ready_to_load { false };
|
||||
uint32_t random_seed;
|
||||
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
|
||||
TCamera pCamera; // parametry kamery
|
||||
TCamera pDebugCamera;
|
||||
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 szDefaultExt{ szTexturesDDS };
|
||||
std::string SceneryFile{ "td.scn" };
|
||||
std::string asHumanCtrlVehicle{ "EU07-424" };
|
||||
std::string local_start_vehicle{ "EU07-424" };
|
||||
int iConvertModels{ 0 }; // tworzenie plików binarnych
|
||||
// logs
|
||||
int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów
|
||||
|
||||
5
Logs.cpp
5
Logs.cpp
@@ -46,12 +46,13 @@ std::string filename_date() {
|
||||
std::snprintf(
|
||||
logbuffer,
|
||||
sizeof(logbuffer),
|
||||
"%d%02d%02d_%02d%02d",
|
||||
"%d%02d%02d_%02d%02d%03d",
|
||||
st.wYear,
|
||||
st.wMonth,
|
||||
st.wDay,
|
||||
st.wHour,
|
||||
st.wMinute );
|
||||
st.wMinute,
|
||||
st.wMilliseconds);
|
||||
|
||||
return std::string( logbuffer );
|
||||
}
|
||||
|
||||
10
Names.h
10
Names.h
@@ -46,8 +46,16 @@ public:
|
||||
auto lookup = m_itemmap.find( Name );
|
||||
if (lookup == m_itemmap.end())
|
||||
return;
|
||||
|
||||
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;
|
||||
// TBD, TODO: remove from m_items?
|
||||
|
||||
|
||||
62
Train.cpp
62
Train.cpp
@@ -4749,11 +4749,12 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm
|
||||
if( false == Train->CabChange( 1 ) ) {
|
||||
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::front ].CouplingFlag, coupling::gangway ) ) {
|
||||
// przejscie do nastepnego pojazdu
|
||||
Global.changeDynObj = Train->DynamicObject->PrevConnected;
|
||||
Global.changeDynObj->MoverParameters->ActiveCab = (
|
||||
TDynamicObject *dynobj = Train->DynamicObject->PrevConnected;
|
||||
dynobj->MoverParameters->ActiveCab = (
|
||||
Train->DynamicObject->PrevConnectedNo ?
|
||||
-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( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ side::rear ].CouplingFlag, coupling::gangway ) ) {
|
||||
// przejscie do nastepnego pojazdu
|
||||
Global.changeDynObj = Train->DynamicObject->NextConnected;
|
||||
Global.changeDynObj->MoverParameters->ActiveCab = (
|
||||
TDynamicObject *dynobj = Train->DynamicObject->NextConnected;
|
||||
dynobj->MoverParameters->ActiveCab = (
|
||||
Train->DynamicObject->NextConnectedNo ?
|
||||
-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
|
||||
bool
|
||||
TTrain::point_inside( Math3D::vector3 const Point ) const {
|
||||
|
||||
1
Train.h
1
Train.h
@@ -670,6 +670,7 @@ private:
|
||||
inline TMoverParameters *Occupied() { return mvOccupied; };
|
||||
inline TMoverParameters const *Occupied() const { return mvOccupied; };
|
||||
void DynamicSet(TDynamicObject *d);
|
||||
void MoveToVehicle(TDynamicObject *target);
|
||||
// checks whether specified point is within boundaries of the active cab
|
||||
bool point_inside( Math3D::vector3 const Point ) const;
|
||||
Math3D::vector3 clamp_inside( Math3D::vector3 const &Point ) const;
|
||||
|
||||
160
application.cpp
160
application.cpp
@@ -9,9 +9,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "application.h"
|
||||
#include "scenarioloadermode.h"
|
||||
#include "drivermode.h"
|
||||
#include "editormode.h"
|
||||
#include "scenarioloadermode.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "simulation.h"
|
||||
@@ -104,20 +104,20 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
|
||||
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_files();
|
||||
if( ( result = init_settings( Argc, Argv ) ) != 0 ) {
|
||||
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 ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if( ( result = init_glfw() ) != 0 ) {
|
||||
return result;
|
||||
}
|
||||
@@ -171,81 +171,94 @@ eu07_application::run() {
|
||||
|
||||
double frameStartTime = Timer::GetTime();
|
||||
|
||||
bool nextloop = true;
|
||||
while (nextloop)
|
||||
{
|
||||
command_queue::commands_map commands_to_exec;
|
||||
command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
|
||||
double slave_sync;
|
||||
if (m_modes[m_modestack.top()]->is_command_processor()) {
|
||||
// active mode is doing real calculations (e.g. drivermode)
|
||||
|
||||
// if we're the server
|
||||
if (m_network && m_network->servers)
|
||||
bool nextloop = true;
|
||||
while (nextloop)
|
||||
{
|
||||
// fetch from network layer command requests received from clients
|
||||
command_queue::commands_map remote_commands = m_network->servers->pop_commands();
|
||||
command_queue::commands_map commands_to_exec;
|
||||
command_queue::commands_map local_commands = simulation::Commands.pop_intercept_queue();
|
||||
double slave_sync;
|
||||
|
||||
// push these into local queue
|
||||
add_to_dequemap(local_commands, remote_commands);
|
||||
}
|
||||
// if we're the server
|
||||
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
|
||||
if (m_network && m_network->client)
|
||||
{
|
||||
// fetch frame info from network layer,
|
||||
auto frame_info = m_network->client->get_next_delta();
|
||||
// push these into local queue
|
||||
add_to_dequemap(local_commands, remote_commands);
|
||||
}
|
||||
|
||||
// use delta and commands received from master
|
||||
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));
|
||||
// if we're slave
|
||||
if (m_network && m_network->client)
|
||||
{
|
||||
// fetch frame info from network layer,
|
||||
auto frame_info = m_network->client->get_next_delta();
|
||||
|
||||
// and send our local commands to master
|
||||
m_network->client->send_commands(local_commands);
|
||||
// use delta and commands received from master
|
||||
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;
|
||||
}
|
||||
// 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
|
||||
simulation::Commands.push_commands(commands_to_exec);
|
||||
// do actual frame processing
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
@@ -269,7 +282,7 @@ eu07_application::run() {
|
||||
}
|
||||
|
||||
if (m_network)
|
||||
m_network->poll();
|
||||
m_network->update();
|
||||
|
||||
auto frametime = Timer::subsystem.mainloop_total.stop();
|
||||
if (Global.minframetime.count() != 0.0f && (Global.minframetime - frametime).count() > 0.0f)
|
||||
@@ -490,7 +503,7 @@ eu07_application::init_files() {
|
||||
#elif __linux__
|
||||
unlink("log.txt");
|
||||
unlink("errors.txt");
|
||||
mkdir("logs", 0664);
|
||||
mkdir("logs", 0755);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -519,7 +532,7 @@ eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||
}
|
||||
else if( token == "-v" ) {
|
||||
if( i + 1 < Argc ) {
|
||||
Global.asHumanCtrlVehicle = ToLower( Argv[ ++i ] );
|
||||
Global.local_start_vehicle = ToLower( Argv[ ++i ] );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -709,6 +722,11 @@ bool eu07_application::init_network() {
|
||||
if (Global.network_conf.is_client) {
|
||||
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;
|
||||
|
||||
@@ -63,6 +63,9 @@ public:
|
||||
virtual
|
||||
void
|
||||
on_event_poll() = 0;
|
||||
virtual
|
||||
bool
|
||||
is_command_processor() = 0;
|
||||
|
||||
protected:
|
||||
// members
|
||||
|
||||
@@ -197,9 +197,9 @@ driver_mode::update() {
|
||||
InOutKey();
|
||||
}
|
||||
|
||||
if( Global.changeDynObj ) {
|
||||
// ABu zmiana pojazdu - przejście do innego
|
||||
ChangeDynamic();
|
||||
if (!FreeFlyModeFlag && simulation::Train->Dynamic() != Camera.m_owner) {
|
||||
// fixup camera after vehicle switch
|
||||
CabView();
|
||||
}
|
||||
|
||||
if( simulation::Train != nullptr )
|
||||
@@ -264,8 +264,8 @@ void
|
||||
driver_mode::enter() {
|
||||
|
||||
TDynamicObject *nPlayerTrain { (
|
||||
( Global.asHumanCtrlVehicle != "ghostview" ) ?
|
||||
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) :
|
||||
( Global.local_start_vehicle != "ghostview" ) ?
|
||||
simulation::Vehicles.find( Global.local_start_vehicle ) :
|
||||
nullptr ) };
|
||||
|
||||
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nullptr );
|
||||
@@ -277,14 +277,14 @@ driver_mode::enter() {
|
||||
|
||||
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());
|
||||
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
|
||||
@@ -301,7 +301,7 @@ driver_mode::enter() {
|
||||
KeyEvents[ 9 ] = simulation::Events.FindEvent( "keyctrl09" );
|
||||
}
|
||||
|
||||
Timer::ResetTimers();
|
||||
Timer::ResetTimers();
|
||||
|
||||
set_picking( Global.ControlPicking );
|
||||
}
|
||||
@@ -377,6 +377,12 @@ driver_mode::on_event_poll() {
|
||||
m_input.poll();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
driver_mode::is_command_processor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
driver_mode::update_camera( double const Deltatime ) {
|
||||
|
||||
@@ -946,65 +952,6 @@ driver_mode::CabView() {
|
||||
train->pMechOffset = Camera.m_owneroffset;
|
||||
}
|
||||
|
||||
void
|
||||
driver_mode::ChangeDynamic() {
|
||||
|
||||
auto *train { simulation::Train };
|
||||
if( train == nullptr ) { return; }
|
||||
|
||||
auto *vehicle { train->Dynamic() };
|
||||
auto *occupied { train->Occupied() };
|
||||
auto *driver { vehicle->Mechanik };
|
||||
// Ra: to nie może być tak robione, to zbytnia proteza jest
|
||||
if( driver ) {
|
||||
// AI może sobie samo pójść
|
||||
if( false == driver->AIControllFlag ) {
|
||||
// tylko jeśli ręcznie prowadzony
|
||||
// jeśli prowadzi AI, to mu nie robimy dywersji!
|
||||
occupied->CabDeactivisation();
|
||||
occupied->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
|
||||
driver_mode::InOutKey()
|
||||
{ // przełączenie widoku z kabiny na zewnętrzny i odwrotnie
|
||||
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override;
|
||||
void
|
||||
on_event_poll() override;
|
||||
bool
|
||||
is_command_processor() override;
|
||||
|
||||
private:
|
||||
// types
|
||||
@@ -86,7 +88,7 @@ private:
|
||||
void update_camera( const double Deltatime );
|
||||
// handles vehicle change flag
|
||||
void OnKeyDown( int cKey );
|
||||
void ChangeDynamic();
|
||||
|
||||
void InOutKey();
|
||||
void CabView();
|
||||
void ExternalView();
|
||||
@@ -99,7 +101,7 @@ private:
|
||||
TCamera Camera;
|
||||
TCamera DebugCamera;
|
||||
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;
|
||||
TDynamicObject *pDynamicNearest { nullptr }; // vehicle nearest to the active camera. TODO: move to camera
|
||||
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
|
||||
|
||||
@@ -262,6 +262,11 @@ editor_mode::on_event_poll() {
|
||||
m_input.poll();
|
||||
}
|
||||
|
||||
|
||||
bool editor_mode::is_command_processor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
editor_mode::mode_translation() const {
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
void
|
||||
on_event_poll() override;
|
||||
bool
|
||||
is_command_processor() override;
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -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
|
||||
auto *vehicle = (
|
||||
pRozkaz->cString[ 1 ] == '*' ?
|
||||
simulation::Vehicles.find( Global.asHumanCtrlVehicle ) :
|
||||
simulation::Train->Dynamic() :
|
||||
simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) );
|
||||
if( vehicle != nullptr ) {
|
||||
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
|
||||
auto *lookup = (
|
||||
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
|
||||
if( lookup == nullptr ) { break; } // nothing found, nothing to do
|
||||
auto *d { lookup };
|
||||
|
||||
@@ -9,10 +9,14 @@ network::tcp::connection::connection(asio::io_context &io_ctx, bool client, size
|
||||
m_header_buffer.resize(8);
|
||||
}
|
||||
|
||||
network::tcp::connection::~connection()
|
||||
{
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void network::tcp::connection::disconnect()
|
||||
{
|
||||
network::connection::disconnect();
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void network::tcp::connection::send_data(std::shared_ptr<std::string> buffer)
|
||||
@@ -176,8 +180,6 @@ void network::tcp::client::connect()
|
||||
if (this->conn)
|
||||
return;
|
||||
|
||||
std::cout << "create sock" << std::endl;
|
||||
|
||||
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));
|
||||
|
||||
@@ -187,7 +189,6 @@ void network::tcp::client::connect()
|
||||
conn->m_socket.set_option(asio::ip::tcp::no_delay(true));
|
||||
conn->m_socket.async_connect(endpoint,
|
||||
std::bind(&client::handle_accept, this, std::placeholders::_1));
|
||||
std::cout << "connect start" <<std::endl;
|
||||
|
||||
this->conn = conn;
|
||||
|
||||
@@ -195,7 +196,6 @@ void network::tcp::client::connect()
|
||||
|
||||
void network::tcp::client::handle_accept(const asio::error_code &err)
|
||||
{
|
||||
std::cout << "connect handl" <<std::endl;
|
||||
if (!err)
|
||||
{
|
||||
conn->connected();
|
||||
@@ -203,6 +203,6 @@ void network::tcp::client::handle_accept(const asio::error_code &err)
|
||||
else
|
||||
{
|
||||
WriteLog(std::string("net: failed to connect: " + err.message()), logtype::net);
|
||||
conn->state = connection::DEAD;
|
||||
conn->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace network::tcp
|
||||
|
||||
public:
|
||||
connection(asio::io_context &io_ctx, bool client = false, size_t counter = 0);
|
||||
~connection();
|
||||
|
||||
virtual void connected() override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
@@ -22,14 +22,14 @@ void network::server_manager::push_delta(double dt, double sync, const command_q
|
||||
if (dt == 0.0 && commands.empty())
|
||||
return;
|
||||
|
||||
for (auto srv : servers)
|
||||
srv->push_delta(dt, sync, commands);
|
||||
|
||||
frame_info msg;
|
||||
msg.dt = dt;
|
||||
msg.sync = sync;
|
||||
msg.commands = commands;
|
||||
|
||||
for (auto srv : servers)
|
||||
srv->push_delta(msg);
|
||||
|
||||
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.poll();
|
||||
|
||||
if (client)
|
||||
client->update();
|
||||
}
|
||||
|
||||
void network::manager::create_server(const std::string &host, uint32_t port)
|
||||
|
||||
@@ -32,6 +32,6 @@ namespace network
|
||||
|
||||
void create_server(const std::string &host, uint32_t port);
|
||||
void connect(const std::string &host, uint32_t port);
|
||||
void poll();
|
||||
void update();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,27 +40,29 @@ void network::connection::catch_up()
|
||||
|
||||
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) {
|
||||
send_messages(messages);
|
||||
backbuffer->seekg(0, std::ios_base::end);
|
||||
state = ACTIVE;
|
||||
backbuffer->seekg(0, std::ios_base::end);
|
||||
return;
|
||||
}
|
||||
|
||||
auto msg = deserialize_message(*backbuffer.get());
|
||||
|
||||
if (packet_counter) {
|
||||
packet_counter--;
|
||||
i--; // TODO: it would be better to skip frames in chunks
|
||||
continue;
|
||||
}
|
||||
|
||||
messages.push_back(deserialize_message(*backbuffer.get()));
|
||||
messages.push_back(msg);
|
||||
}
|
||||
|
||||
send_messages(messages);
|
||||
|
||||
backbuffer_pos = backbuffer->tellg();
|
||||
|
||||
backbuffer->seekg(0, std::ios_base::end);
|
||||
|
||||
send_messages(messages);
|
||||
}
|
||||
|
||||
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(); ) {
|
||||
if ((*it)->state == connection::DEAD) {
|
||||
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) {
|
||||
auto cmd = dynamic_cast<const client_hello&>(msg);
|
||||
|
||||
if (cmd.version != 1) {
|
||||
conn->disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
server_hello reply;
|
||||
reply.seed = Global.random_seed;
|
||||
conn->state = connection::CATCHING_UP;
|
||||
@@ -167,20 +169,24 @@ void network::server::handle_message(std::shared_ptr<connection> conn, const mes
|
||||
|
||||
// ------------
|
||||
|
||||
// client
|
||||
int zzz = 20;
|
||||
std::tuple<double, double, command_queue::commands_map> network::client::get_next_delta()
|
||||
void network::client::update()
|
||||
{
|
||||
if (conn && conn->state == connection::DEAD) {
|
||||
conn.reset();
|
||||
}
|
||||
|
||||
if (!conn) {
|
||||
zzz--;
|
||||
if (zzz < 0)
|
||||
if (!reconnect_delay) {
|
||||
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()) {
|
||||
return std::tuple<double, double,
|
||||
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();
|
||||
delta_queue.pop();
|
||||
|
||||
auto &delta = entry.second;
|
||||
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);
|
||||
conn->state = connection::ACTIVE;
|
||||
|
||||
Global.random_seed = cmd.seed;
|
||||
Global.random_engine.seed(Global.random_seed);
|
||||
Global.ready_to_load = true;
|
||||
if (!Global.ready_to_load) {
|
||||
Global.random_seed = cmd.seed;
|
||||
Global.random_engine.seed(Global.random_seed);
|
||||
Global.ready_to_load = true;
|
||||
}
|
||||
|
||||
WriteLog("net: accept received", logtype::net);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace network
|
||||
friend class client;
|
||||
|
||||
private:
|
||||
const size_t CATCHUP_PACKETS = 100;
|
||||
const int CATCHUP_PACKETS = 100;
|
||||
|
||||
/*
|
||||
std::queue<
|
||||
@@ -74,7 +74,7 @@ namespace network
|
||||
|
||||
public:
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -85,12 +85,16 @@ namespace network
|
||||
void handle_message(std::shared_ptr<connection> conn, const message &msg);
|
||||
std::shared_ptr<connection> conn;
|
||||
size_t resume_frame_counter = 0;
|
||||
size_t reconnect_delay = 0;
|
||||
|
||||
const size_t RECONNECT_DELAY_FRAMES = 60;
|
||||
|
||||
std::queue<
|
||||
std::pair<std::chrono::high_resolution_clock::time_point,
|
||||
frame_info>> delta_queue;
|
||||
|
||||
public:
|
||||
void update();
|
||||
std::tuple<double, double, command_queue::commands_map> get_next_delta();
|
||||
void send_commands(command_queue::commands_map commands);
|
||||
};
|
||||
|
||||
@@ -2114,9 +2114,6 @@ bool opengl_renderer::Render(TDynamicObject *Dynamic)
|
||||
m_sunlight.apply_intensity(Dynamic->fShade);
|
||||
}
|
||||
|
||||
// calc_motion = true;
|
||||
// std::cout << glm::to_string(glm::vec3(Dynamic->get_velocity_vec())) << std::endl;
|
||||
|
||||
// render
|
||||
if (Dynamic->mdLowPolyInt)
|
||||
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}, {});
|
||||
|
||||
// post-render cleanup
|
||||
// calc_motion = false;
|
||||
|
||||
if (Dynamic->fShade > 0.0f)
|
||||
{
|
||||
|
||||
@@ -35,27 +35,40 @@ scenarioloader_mode::init() {
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
scenarioloader_mode::update() {
|
||||
if (!Global.ready_to_load)
|
||||
// waiting for network connection
|
||||
return true;
|
||||
|
||||
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 ) ) {
|
||||
WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" );
|
||||
// TODO: implement and use next mode cue
|
||||
Global.random_seed = std::random_device{}();
|
||||
Global.random_engine.seed(Global.random_seed);
|
||||
Application.pop_mode();
|
||||
Application.push_mode( eu07_application::mode::driver );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "Bad init: scenario loading failed" );
|
||||
Application.pop_mode();
|
||||
}
|
||||
try {
|
||||
if (simulation::State.deserialize_continue(state))
|
||||
return true;
|
||||
}
|
||||
catch (invalid_scenery_exception &e) {
|
||||
ErrorLog( "Bad init: scenario loading failed" );
|
||||
Application.pop_mode();
|
||||
}
|
||||
|
||||
WriteLog( "Scenario loading time: " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>( ( std::chrono::system_clock::now() - timestart ) ).count() ) + " seconds" );
|
||||
// TODO: implement and use next mode cue
|
||||
|
||||
Application.pop_mode();
|
||||
Application.push_mode( eu07_application::mode::driver );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scenarioloader_mode::is_command_processor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
scenarioloader_mode::enter() {
|
||||
|
||||
@@ -10,8 +10,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include "applicationmode.h"
|
||||
#include "simulation.h"
|
||||
|
||||
class scenarioloader_mode : public application_mode {
|
||||
std::shared_ptr<simulation::deserializer_state> state;
|
||||
std::chrono::system_clock::time_point timestart;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
@@ -40,4 +43,6 @@ public:
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
void
|
||||
on_event_poll() override { ; }
|
||||
bool
|
||||
is_command_processor() override;
|
||||
};
|
||||
|
||||
@@ -45,10 +45,16 @@ TTrain *Train { nullptr };
|
||||
uint16_t prev_train_id { 0 };
|
||||
bool is_ready { false };
|
||||
|
||||
bool
|
||||
state_manager::deserialize( std::string const &Scenariofile ) {
|
||||
std::shared_ptr<deserializer_state>
|
||||
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
|
||||
|
||||
11
simulation.h
11
simulation.h
@@ -26,9 +26,12 @@ public:
|
||||
update( double Deltatime, int Iterationcount );
|
||||
void
|
||||
update_clocks();
|
||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// starts deserialization from specified file, returns context pointer on success, throws otherwise
|
||||
std::shared_ptr<deserializer_state>
|
||||
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
|
||||
void
|
||||
export_as_text( std::string const &Scenariofile ) const;
|
||||
@@ -63,6 +66,8 @@ extern TTrain *Train;
|
||||
extern uint16_t prev_train_id;
|
||||
extern bool is_ready;
|
||||
|
||||
class deserializer_state;
|
||||
|
||||
} // simulation
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -25,98 +25,87 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
namespace simulation {
|
||||
|
||||
bool
|
||||
state_serializer::deserialize( std::string const &Scenariofile ) {
|
||||
std::shared_ptr<deserializer_state>
|
||||
state_serializer::deserialize_begin( std::string const &Scenariofile ) {
|
||||
|
||||
// TODO: move initialization to separate routine so we can reuse it
|
||||
SafeDelete( 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
|
||||
// if this fails, fall back on the legacy text format
|
||||
scene::scratch_data importscratchpad;
|
||||
importscratchpad.name = Scenariofile;
|
||||
state->scratchpad.name = Scenariofile;
|
||||
if( Scenariofile != "$.scn" ) {
|
||||
// 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
|
||||
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 );
|
||||
if( ( false == importscratchpad.binary.terrain )
|
||||
&& ( 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( Scenariofile );
|
||||
}
|
||||
return true;
|
||||
// prepare deserialization function table
|
||||
// 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 } };
|
||||
|
||||
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
|
||||
void
|
||||
state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
// prepare deserialization function table
|
||||
// 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 ) ) );
|
||||
}
|
||||
// continues deserialization for given context, amount limited by time, returns true if needs to be called again
|
||||
bool
|
||||
state_serializer::deserialize_continue(std::shared_ptr<deserializer_state> state) {
|
||||
cParser &Input = state->input;
|
||||
scene::scratch_data &Scratchpad = state->scratchpad;
|
||||
|
||||
// deserialize content from the provided input
|
||||
auto
|
||||
timelast { std::chrono::steady_clock::now() },
|
||||
timenow { timelast };
|
||||
auto timelast { std::chrono::steady_clock::now() };
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( false == token.empty() ) {
|
||||
|
||||
auto lookup = functionmap.find( token );
|
||||
if( lookup != functionmap.end() ) {
|
||||
auto lookup = state->functionmap.find( token );
|
||||
if( lookup != state->functionmap.end() ) {
|
||||
lookup->second();
|
||||
}
|
||||
else {
|
||||
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 ) {
|
||||
timelast = timenow;
|
||||
glfwPollEvents();
|
||||
Application.set_progress( Input.getProgress(), Input.getFullProgress() );
|
||||
GfxRenderer.Render();
|
||||
GfxRenderer.SwapBuffers();
|
||||
return true;
|
||||
}
|
||||
|
||||
token = Input.getToken<std::string>();
|
||||
@@ -129,6 +118,15 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
||||
|
||||
if (Global.map_enabled)
|
||||
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
|
||||
|
||||
@@ -14,21 +14,37 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
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 {
|
||||
|
||||
public:
|
||||
|
||||
// methods
|
||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
||||
bool
|
||||
deserialize( std::string const &Scenariofile );
|
||||
// starts deserialization from specified file, returns context pointer on success, throws otherwise
|
||||
std::shared_ptr<deserializer_state>
|
||||
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
|
||||
void
|
||||
export_as_text( std::string const &Scenariofile ) const;
|
||||
|
||||
private:
|
||||
// methods
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
// restores class data from provided stream
|
||||
void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
|
||||
Reference in New Issue
Block a user