mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-23 13:19:19 +02:00
milek7/sim branch network code import
This commit is contained in:
@@ -40,6 +40,7 @@ class memory_table;
|
|||||||
class powergridsource_table;
|
class powergridsource_table;
|
||||||
class instance_table;
|
class instance_table;
|
||||||
class vehicle_table;
|
class vehicle_table;
|
||||||
|
class train_table;
|
||||||
struct light_array;
|
struct light_array;
|
||||||
class particle_manager;
|
class particle_manager;
|
||||||
struct dictionary_source;
|
struct dictionary_source;
|
||||||
@@ -77,4 +78,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
|
||||||
|
|||||||
@@ -1862,11 +1862,9 @@ void TController::Activation()
|
|||||||
}
|
}
|
||||||
if (pVehicle != old)
|
if (pVehicle != old)
|
||||||
{ // jeśli zmieniony został pojazd prowadzony
|
{ // jeśli zmieniony został pojazd prowadzony
|
||||||
if( ( simulation::Train )
|
TTrain *train = simulation::Trains.find(old->name());
|
||||||
&& ( simulation::Train->Dynamic() == old ) ) {
|
if (train)
|
||||||
// ewentualna zmiana kabiny użytkownikowi
|
train->MoveToVehicle(pVehicle);
|
||||||
Global.changeDynObj = pVehicle; // uruchomienie protezy
|
|
||||||
}
|
|
||||||
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT
|
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT
|
||||||
}
|
}
|
||||||
if( mvControlling->EngineType == TEngineType::DieselEngine ) {
|
if( mvControlling->EngineType == TEngineType::DieselEngine ) {
|
||||||
|
|||||||
57
DynObj.cpp
57
DynObj.cpp
@@ -1615,6 +1615,36 @@ TDynamicObject::~TDynamicObject() {
|
|||||||
SafeDeleteArray( pAnimated ); // lista animowanych submodeli
|
SafeDeleteArray( pAnimated ); // lista animowanych submodeli
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TDynamicObject::place_on_track(TTrack *Track, double fDist, bool Reversed)
|
||||||
|
{
|
||||||
|
for( auto &axle : m_axlesounds ) {
|
||||||
|
// wyszukiwanie osi (0 jest na końcu, dlatego dodajemy długość?)
|
||||||
|
axle.distance = (
|
||||||
|
Reversed ?
|
||||||
|
-axle.offset :
|
||||||
|
( axle.offset + MoverParameters->Dim.L ) ) + fDist;
|
||||||
|
}
|
||||||
|
double fAxleDistHalf = fAxleDist * 0.5;
|
||||||
|
// przesuwanie pojazdu tak, aby jego początek był we wskazanym miejcu
|
||||||
|
fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół długości pojazdu, bo ustawiamy jego środek (zliczanie na minus)
|
||||||
|
switch (iNumAxles) {
|
||||||
|
// Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane
|
||||||
|
case 2: // ustawianie osi na torze
|
||||||
|
Axle0.Init(Track, this, iDirection ? 1 : -1);
|
||||||
|
Axle0.Reset();
|
||||||
|
Axle0.Move((iDirection ? fDist : -fDist) + fAxleDistHalf, false);
|
||||||
|
Axle1.Init(Track, this, iDirection ? 1 : -1);
|
||||||
|
Axle1.Reset();
|
||||||
|
Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, false); // false, żeby nie generować eventów
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// potrzebne do wyliczenia aktualnej pozycji; nie może być zero, bo nie przeliczy pozycji
|
||||||
|
// teraz jeszcze trzeba przypisać pojazdy do nowego toru, bo przesuwanie początkowe osi nie
|
||||||
|
// zrobiło tego
|
||||||
|
Move( 0.0001 );
|
||||||
|
ABuCheckMyTrack(); // zmiana toru na ten, co oś Axle0 (oś z przodu)
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424"
|
||||||
std::string BaseDir, // z którego katalogu wczytany, np. "PKP/EU07"
|
std::string BaseDir, // z którego katalogu wczytany, np. "PKP/EU07"
|
||||||
@@ -2190,7 +2220,7 @@ TDynamicObject::create_controller( std::string const Type, bool const Trainset )
|
|||||||
|
|
||||||
if( Type == "" ) { return; }
|
if( Type == "" ) { return; }
|
||||||
|
|
||||||
if( asName == Global.asHumanCtrlVehicle ) {
|
if( asName == Global.local_start_vehicle ) {
|
||||||
// jeśli pojazd wybrany do prowadzenia
|
// jeśli pojazd wybrany do prowadzenia
|
||||||
if( MoverParameters->EngineType != TEngineType::Dumb ) {
|
if( MoverParameters->EngineType != TEngineType::Dumb ) {
|
||||||
// wsadzamy tam sterującego
|
// wsadzamy tam sterującego
|
||||||
@@ -6542,6 +6572,20 @@ glm::dvec3 TDynamicObject::get_future_movement() const {
|
|||||||
return m_future_movement;
|
return m_future_movement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TDynamicObject::move_set(double distance)
|
||||||
|
{
|
||||||
|
TDynamicObject *d = this;
|
||||||
|
while( d ) {
|
||||||
|
d->Move( distance * d->DirectionGet() );
|
||||||
|
d = d->Next(); // pozostałe też
|
||||||
|
}
|
||||||
|
d = Prev();
|
||||||
|
while( d ) {
|
||||||
|
d->Move( distance * d->DirectionGet() );
|
||||||
|
d = d->Prev(); // w drugą stronę też
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns type of the nearest functional power source present in the trainset
|
// returns type of the nearest functional power source present in the trainset
|
||||||
TPowerSource
|
TPowerSource
|
||||||
TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const {
|
TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const {
|
||||||
@@ -6640,13 +6684,13 @@ TDynamicObject::update_shake( double const Timedelta ) {
|
|||||||
|
|
||||||
auto shake { 1.25 * ShakeSpring.ComputateForces( shakevector, ShakeState.offset ) };
|
auto shake { 1.25 * ShakeSpring.ComputateForces( shakevector, ShakeState.offset ) };
|
||||||
|
|
||||||
if( Random( iVel ) > 25.0 ) {
|
if( LocalRandom( iVel ) > 25.0 ) {
|
||||||
// extra shake at increased velocity
|
// extra shake at increased velocity
|
||||||
shake += ShakeSpring.ComputateForces(
|
shake += ShakeSpring.ComputateForces(
|
||||||
Math3D::vector3(
|
Math3D::vector3(
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.x,
|
( LocalRandom( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.x,
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.y,
|
( LocalRandom( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.y,
|
||||||
( Random( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.z )
|
( LocalRandom( iVel * 2 ) - iVel ) / ( ( iVel * 2 ) * 4 ) * BaseShake.jolt_scale.z )
|
||||||
// * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ) // scale to 75-150% based on track quality
|
// * (( 200 - DynamicObject->MyTrack->iQualityFlag ) * 0.0075 ) // scale to 75-150% based on track quality
|
||||||
* 1.25,
|
* 1.25,
|
||||||
ShakeState.offset );
|
ShakeState.offset );
|
||||||
@@ -6986,7 +7030,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub
|
|||||||
if( ( volume < 1.0 )
|
if( ( volume < 1.0 )
|
||||||
&& ( Vehicle.EnginePower < 100 ) ) {
|
&& ( Vehicle.EnginePower < 100 ) ) {
|
||||||
|
|
||||||
auto const volumevariation { Random( 100 ) * Vehicle.enrot / ( 1 + Vehicle.nmax ) };
|
auto const volumevariation { LocalRandom( 100 ) * Vehicle.enrot / ( 1 + Vehicle.nmax ) };
|
||||||
if( volumevariation < 2 ) {
|
if( volumevariation < 2 ) {
|
||||||
volume += volumevariation / 200;
|
volume += volumevariation / 200;
|
||||||
}
|
}
|
||||||
@@ -7362,6 +7406,7 @@ vehicle_table::erase_disabled() {
|
|||||||
// TBD, TODO: kill vehicle sounds
|
// TBD, TODO: kill vehicle sounds
|
||||||
SafeDelete( simulation::Train );
|
SafeDelete( simulation::Train );
|
||||||
}
|
}
|
||||||
|
simulation::Trains.purge(vehicle->name());
|
||||||
// remove potential entries in the light array
|
// remove potential entries in the light array
|
||||||
simulation::Lights.remove( vehicle );
|
simulation::Lights.remove( vehicle );
|
||||||
/*
|
/*
|
||||||
|
|||||||
2
DynObj.h
2
DynObj.h
@@ -544,6 +544,7 @@ private:
|
|||||||
|
|
||||||
TDynamicObject();
|
TDynamicObject();
|
||||||
~TDynamicObject();
|
~TDynamicObject();
|
||||||
|
void place_on_track(TTrack *Track, double fDist, bool Reversed);
|
||||||
// zwraca długość pojazdu albo 0, jeśli błąd
|
// zwraca długość pojazdu albo 0, jeśli błąd
|
||||||
double Init(
|
double Init(
|
||||||
std::string Name, std::string BaseDir, std::string asReplacableSkin, std::string Type_Name,
|
std::string Name, std::string BaseDir, std::string asReplacableSkin, std::string Type_Name,
|
||||||
@@ -672,6 +673,7 @@ private:
|
|||||||
material_handle DestinationFind( std::string Destination );
|
material_handle DestinationFind( std::string Destination );
|
||||||
void OverheadTrack(float o);
|
void OverheadTrack(float o);
|
||||||
glm::dvec3 get_future_movement() const;
|
glm::dvec3 get_future_movement() const;
|
||||||
|
void move_set(double distance);
|
||||||
|
|
||||||
double MED[9][8]; // lista zmiennych do debugowania hamulca ED
|
double MED[9][8]; // lista zmiennych do debugowania hamulca ED
|
||||||
static std::string const MED_labels[ 8 ];
|
static std::string const MED_labels[ 8 ];
|
||||||
|
|||||||
62
EvLaunch.cpp
62
EvLaunch.cpp
@@ -31,20 +31,23 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
// encodes expected key in a short, where low byte represents the actual key,
|
// encodes expected key in a short, where low byte represents the actual key,
|
||||||
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
|
// and the high byte holds modifiers: 0x1 = shift, 0x2 = ctrl, 0x4 = alt
|
||||||
int vk_to_glfw_key( int const Keycode ) {
|
int vk_to_glfw_key( int const Keycode ) {
|
||||||
|
char modifier = 0;
|
||||||
|
char key = 0;
|
||||||
|
|
||||||
#ifdef _WIN32
|
if (Keycode < 'A') {
|
||||||
auto const code = VkKeyScan( Keycode );
|
key = Keycode;
|
||||||
char key = code & 0xff;
|
} else if (Keycode <= 'Z') {
|
||||||
char shiftstate = ( code & 0xff00 ) >> 8;
|
key = Keycode;
|
||||||
|
modifier = GLFW_MOD_SHIFT;
|
||||||
|
} else if (Keycode < 'a') {
|
||||||
|
key = Keycode;
|
||||||
|
} else if (Keycode <= 'z') {
|
||||||
|
key = Keycode - 32;
|
||||||
|
} else {
|
||||||
|
ErrorLog("unknown key: " + std::to_string(Keycode));
|
||||||
|
}
|
||||||
|
|
||||||
if( (key >= 'A') && (key <= 'Z') ) {
|
return ((int)modifier << 8) | key;
|
||||||
key = GLFW_KEY_A + key - 'A';
|
|
||||||
}
|
|
||||||
else if( ( key >= '0' ) && ( key <= '9' ) ) {
|
|
||||||
key = GLFW_KEY_0 + key - '0';
|
|
||||||
}
|
|
||||||
return key + ( shiftstate << 8 );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TEventLauncher::Load(cParser *parser)
|
bool TEventLauncher::Load(cParser *parser)
|
||||||
@@ -152,24 +155,33 @@ bool TEventLauncher::Load(cParser *parser)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TEventLauncher::check_activation_key() {
|
||||||
|
if (iKey <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char key = iKey & 0xff;
|
||||||
|
|
||||||
|
bool result = Console::Pressed(key);
|
||||||
|
|
||||||
|
char modifier = iKey >> 8;
|
||||||
|
if (modifier & GLFW_MOD_SHIFT)
|
||||||
|
result &= Global.shiftState;
|
||||||
|
if (modifier & GLFW_MOD_CONTROL)
|
||||||
|
result &= Global.ctrlState;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool TEventLauncher::check_activation() {
|
bool TEventLauncher::check_activation() {
|
||||||
|
|
||||||
auto bCond { false };
|
auto bCond { false };
|
||||||
|
|
||||||
if( iKey > 0 ) {
|
if (DeltaTime == 10000.0) {
|
||||||
if( iKey > 255 ) {
|
if (UpdatedTime == 0.0)
|
||||||
// key and modifier
|
bCond = true;
|
||||||
auto const modifier = ( iKey & 0xff00 ) >> 8;
|
UpdatedTime = 1.0;
|
||||||
bCond = ( Console::Pressed( iKey & 0xff ) )
|
|
||||||
&& ( ( modifier & 1 ) ? Global.shiftState : true )
|
|
||||||
&& ( ( modifier & 2 ) ? Global.ctrlState : true );
|
|
||||||
}
|
}
|
||||||
else {
|
else if( DeltaTime > 0 ) {
|
||||||
// just key
|
|
||||||
bCond = ( Console::Pressed( iKey & 0xff ) ); // czy klawisz wciśnięty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( DeltaTime > 0 ) {
|
|
||||||
if( UpdatedTime > DeltaTime ) {
|
if( UpdatedTime > DeltaTime ) {
|
||||||
UpdatedTime = 0; // naliczanie od nowa
|
UpdatedTime = 0; // naliczanie od nowa
|
||||||
bCond = true;
|
bCond = true;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public:
|
|||||||
|
|
||||||
// methods
|
// methods
|
||||||
bool Load( cParser *parser );
|
bool Load( cParser *parser );
|
||||||
|
bool check_activation_key();
|
||||||
bool check_activation();
|
bool check_activation();
|
||||||
// checks conditions associated with the event. returns: true if the conditions are met
|
// checks conditions associated with the event. returns: true if the conditions are met
|
||||||
bool check_conditions();
|
bool check_conditions();
|
||||||
|
|||||||
13
Event.cpp
13
Event.cpp
@@ -1966,13 +1966,18 @@ event_manager::update() {
|
|||||||
CheckQuery();
|
CheckQuery();
|
||||||
// test list of global events for possible new additions to the queue
|
// test list of global events for possible new additions to the queue
|
||||||
for( auto *launcher : m_launcherqueue ) {
|
for( auto *launcher : m_launcherqueue ) {
|
||||||
|
if (launcher->check_conditions() && launcher->Event1) {
|
||||||
if( true == ( launcher->check_activation() && launcher->check_conditions() ) ) {
|
|
||||||
// NOTE: we're presuming global events aren't going to use event2
|
// NOTE: we're presuming global events aren't going to use event2
|
||||||
WriteLog( "Eventlauncher " + launcher->name() );
|
|
||||||
if( launcher->Event1 ) {
|
if (launcher->check_activation()) {
|
||||||
|
WriteLog( "Eventlauncher: " + launcher->name() );
|
||||||
AddToQuery( launcher->Event1, nullptr );
|
AddToQuery( launcher->Event1, nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (launcher->check_activation_key()) {
|
||||||
|
WriteLog( "Eventlauncher: " + launcher->name() );
|
||||||
|
m_relay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &launcher->Event1->name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
Event.h
6
Event.h
@@ -77,6 +77,7 @@ public:
|
|||||||
virtual glm::dvec3 input_location() const;
|
virtual glm::dvec3 input_location() const;
|
||||||
void group( scene::group_handle Group );
|
void group( scene::group_handle Group );
|
||||||
scene::group_handle group() const;
|
scene::group_handle group() const;
|
||||||
|
std::string const &name() const { return m_name; }
|
||||||
// members
|
// members
|
||||||
basic_event *m_next { nullptr }; // następny w kolejce // TODO: replace with event list in the manager
|
basic_event *m_next { nullptr }; // następny w kolejce // TODO: replace with event list in the manager
|
||||||
basic_event *m_sibling { nullptr }; // kolejny event z tą samą nazwą - od wersji 378
|
basic_event *m_sibling { nullptr }; // kolejny event z tą samą nazwą - od wersji 378
|
||||||
@@ -584,6 +585,10 @@ public:
|
|||||||
// legacy method, returns pointer to specified event, or null
|
// legacy method, returns pointer to specified event, or null
|
||||||
basic_event *
|
basic_event *
|
||||||
FindEvent( std::string const &Name );
|
FindEvent( std::string const &Name );
|
||||||
|
inline TEventLauncher* FindEventlauncher(std::string const &Name) {
|
||||||
|
auto ptr = m_inputdrivenlaunchers.find(Name);
|
||||||
|
return ptr ? ptr : m_radiodrivenlaunchers.find(Name);
|
||||||
|
}
|
||||||
// legacy method, inserts specified event in the event query
|
// legacy method, inserts specified event in the event query
|
||||||
bool
|
bool
|
||||||
AddToQuery( basic_event *Event, TDynamicObject const *Owner );
|
AddToQuery( basic_event *Event, TDynamicObject const *Owner );
|
||||||
@@ -618,6 +623,7 @@ private:
|
|||||||
basic_table<TEventLauncher> m_inputdrivenlaunchers;
|
basic_table<TEventLauncher> m_inputdrivenlaunchers;
|
||||||
basic_table<TEventLauncher> m_radiodrivenlaunchers;
|
basic_table<TEventLauncher> m_radiodrivenlaunchers;
|
||||||
eventlauncher_sequence m_launcherqueue;
|
eventlauncher_sequence m_launcherqueue;
|
||||||
|
command_relay m_relay;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
37
Globals.cpp
37
Globals.cpp
@@ -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" ) {
|
||||||
|
|
||||||
@@ -768,6 +768,18 @@ global_settings::ConfigParse(cParser &Parser) {
|
|||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
Parser >> gfx_shadowmap_enabled;
|
Parser >> gfx_shadowmap_enabled;
|
||||||
}
|
}
|
||||||
|
else if (token == "fpslimit")
|
||||||
|
{
|
||||||
|
Parser.getTokens(1);
|
||||||
|
float fpslimit;
|
||||||
|
Parser >> fpslimit;
|
||||||
|
minframetime = std::chrono::duration<float>(1.0f / fpslimit);
|
||||||
|
}
|
||||||
|
else if (token == "randomseed")
|
||||||
|
{
|
||||||
|
Parser.getTokens(1);
|
||||||
|
Parser >> Global.random_seed;
|
||||||
|
}
|
||||||
else if (token == "gfx.envmap.enabled")
|
else if (token == "gfx.envmap.enabled")
|
||||||
{
|
{
|
||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
@@ -852,6 +864,29 @@ global_settings::ConfigParse(cParser &Parser) {
|
|||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
Parser >> python_mipmaps;
|
Parser >> python_mipmaps;
|
||||||
}
|
}
|
||||||
|
else if (token == "network.server")
|
||||||
|
{
|
||||||
|
Parser.getTokens(2);
|
||||||
|
|
||||||
|
std::string backend;
|
||||||
|
std::string conf;
|
||||||
|
Parser >> backend >> conf;
|
||||||
|
|
||||||
|
network_servers.push_back(std::make_pair(backend, conf));
|
||||||
|
}
|
||||||
|
else if (token == "network.client")
|
||||||
|
{
|
||||||
|
Parser.getTokens(2);
|
||||||
|
|
||||||
|
network_client.emplace();
|
||||||
|
Parser >> network_client->first;
|
||||||
|
Parser >> network_client->second;
|
||||||
|
}
|
||||||
|
else if (token == "execonexit") {
|
||||||
|
Parser.getTokens(1);
|
||||||
|
Parser >> exec_on_exit;
|
||||||
|
std::replace(std::begin(exec_on_exit), std::end(exec_on_exit), '_', ' ');
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
else if (token == "crashdamage") {
|
else if (token == "crashdamage") {
|
||||||
Parser.getTokens(1);
|
Parser.getTokens(1);
|
||||||
|
|||||||
24
Globals.h
24
Globals.h
@@ -28,8 +28,11 @@ struct global_settings {
|
|||||||
bool shiftState{ false }; //m7todo: brzydko
|
bool shiftState{ false }; //m7todo: brzydko
|
||||||
bool ctrlState{ false };
|
bool ctrlState{ false };
|
||||||
bool altState{ false };
|
bool altState{ false };
|
||||||
std::mt19937 random_engine{ std::mt19937( static_cast<unsigned int>( std::time( NULL ) ) ) };
|
std::mt19937 random_engine;
|
||||||
std::mt19937 local_random_engine{ std::mt19937( static_cast<unsigned int>( std::time( NULL ) ) ) };
|
std::mt19937 local_random_engine;
|
||||||
|
bool ready_to_load { false };
|
||||||
|
std::time_t starting_timestamp = 0; // starting time, in local timezone
|
||||||
|
uint32_t random_seed = 0;
|
||||||
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
|
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
|
||||||
TCamera pCamera; // parametry kamery
|
TCamera pCamera; // parametry kamery
|
||||||
TCamera pDebugCamera;
|
TCamera pDebugCamera;
|
||||||
@@ -63,7 +66,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
|
||||||
bool file_binary_terrain{ true }; // enable binary terrain (de)serialization
|
bool file_binary_terrain{ true }; // enable binary terrain (de)serialization
|
||||||
// logs
|
// logs
|
||||||
@@ -188,6 +191,13 @@ struct global_settings {
|
|||||||
std::string asVersion{ "UNKNOWN" }; // z opisem
|
std::string asVersion{ "UNKNOWN" }; // z opisem
|
||||||
// TODO: move these to relevant areas
|
// TODO: move these to relevant areas
|
||||||
bool render_cab = true;
|
bool render_cab = true;
|
||||||
|
|
||||||
|
std::chrono::duration<float> minframetime {0.0f};
|
||||||
|
|
||||||
|
std::string fullscreen_monitor;
|
||||||
|
|
||||||
|
bool python_mipmaps = true;
|
||||||
|
|
||||||
int gfx_framebuffer_width = -1;
|
int gfx_framebuffer_width = -1;
|
||||||
int gfx_framebuffer_height = -1;
|
int gfx_framebuffer_height = -1;
|
||||||
int gfx_framebuffer_fidelity = -1;
|
int gfx_framebuffer_fidelity = -1;
|
||||||
@@ -202,8 +212,12 @@ struct global_settings {
|
|||||||
bool gfx_extraeffects = true;
|
bool gfx_extraeffects = true;
|
||||||
bool gfx_shadergamma = false;
|
bool gfx_shadergamma = false;
|
||||||
bool gfx_usegles = false;
|
bool gfx_usegles = false;
|
||||||
std::string fullscreen_monitor;
|
|
||||||
bool python_mipmaps = true;
|
std::string exec_on_exit;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> network_servers;
|
||||||
|
std::optional<std::pair<std::string, std::string>> network_client;
|
||||||
|
double desync = 0.0;
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
void LoadIniFile( std::string asFileName );
|
void LoadIniFile( std::string asFileName );
|
||||||
|
|||||||
2
Logs.h
2
Logs.h
@@ -20,7 +20,7 @@ enum logtype : unsigned int {
|
|||||||
// lua = ( 1 << 4 ),
|
// lua = ( 1 << 4 ),
|
||||||
material = ( 1 << 5 ),
|
material = ( 1 << 5 ),
|
||||||
shader = ( 1 << 6 ),
|
shader = ( 1 << 6 ),
|
||||||
// net = ( 1 << 7 )
|
net = ( 1 << 7 )
|
||||||
};
|
};
|
||||||
|
|
||||||
void WriteLog( const char *str, logtype const Type = logtype::generic );
|
void WriteLog( const char *str, logtype const Type = logtype::generic );
|
||||||
|
|||||||
37
Names.h
37
Names.h
@@ -38,6 +38,43 @@ public:
|
|||||||
// item with this name already exists; update mapping to point to the new one, for backward compatibility
|
// item with this name already exists; update mapping to point to the new one, for backward compatibility
|
||||||
mapping.first->second = itemhandle;
|
mapping.first->second = itemhandle;
|
||||||
return false; }
|
return false; }
|
||||||
|
void purge (std::string const &Name)
|
||||||
|
{
|
||||||
|
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?
|
||||||
|
|
||||||
|
m_itemmap.erase(lookup);
|
||||||
|
}
|
||||||
|
uint32_t find_id( std::string const &Name) const {
|
||||||
|
auto lookup = m_itemmap.find( Name );
|
||||||
|
return (
|
||||||
|
lookup != m_itemmap.end() ?
|
||||||
|
lookup->second :
|
||||||
|
-1 );
|
||||||
|
}
|
||||||
|
void purge (Type_ *Item)
|
||||||
|
{
|
||||||
|
for (auto it = m_items.begin(); it != m_items.end(); it++) {
|
||||||
|
if (*it == Item) {
|
||||||
|
delete *it;
|
||||||
|
*it = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// locates item with specified name. returns pointer to the item, or nullptr
|
// locates item with specified name. returns pointer to the item, or nullptr
|
||||||
Type_ *
|
Type_ *
|
||||||
find( std::string const &Name ) const {
|
find( std::string const &Name ) const {
|
||||||
|
|||||||
46
Timer.cpp
46
Timer.cpp
@@ -15,13 +15,14 @@ namespace Timer {
|
|||||||
|
|
||||||
subsystem_stopwatches subsystem;
|
subsystem_stopwatches subsystem;
|
||||||
|
|
||||||
double DeltaTime, DeltaRenderTime;
|
double DeltaTime = 0.0, DeltaRenderTime = 0.0;
|
||||||
double fFPS{ 0.0f };
|
double fFPS{ 0.0f };
|
||||||
double fLastTime{ 0.0f };
|
double fLastTime{ 0.0f };
|
||||||
DWORD dwFrames{ 0 };
|
DWORD dwFrames{ 0 };
|
||||||
double fSimulationTime{ 0.0 };
|
double fSimulationTime{ 0.0 };
|
||||||
double fSoundTimer{ 0.0 };
|
double fSoundTimer{ 0.0 };
|
||||||
double fSinceStart{ 0.0 };
|
double fSinceStart{ 0.0 };
|
||||||
|
double override_delta = -1.0f;
|
||||||
|
|
||||||
double GetTime()
|
double GetTime()
|
||||||
{
|
{
|
||||||
@@ -30,6 +31,8 @@ double GetTime()
|
|||||||
|
|
||||||
double GetDeltaTime()
|
double GetDeltaTime()
|
||||||
{ // czas symulacji (stoi gdy pauza)
|
{ // czas symulacji (stoi gdy pauza)
|
||||||
|
if (override_delta != -1.0f)
|
||||||
|
return override_delta;
|
||||||
return DeltaTime;
|
return DeltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,35 +41,31 @@ double GetDeltaRenderTime()
|
|||||||
return DeltaRenderTime;
|
return DeltaRenderTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDeltaTime(double t)
|
void set_delta_override(double t)
|
||||||
{
|
{
|
||||||
DeltaTime = t;
|
override_delta = t;
|
||||||
}
|
|
||||||
|
|
||||||
bool GetSoundTimer()
|
|
||||||
{ // Ra: być może, by dźwięki nie modyfikowały się zbyt często, po 0.1s zeruje się ten licznik
|
|
||||||
return (fSoundTimer == 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
double GetFPS()
|
|
||||||
{
|
|
||||||
return fFPS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetTimers()
|
void ResetTimers()
|
||||||
{
|
{
|
||||||
UpdateTimers( Global.iPause != 0 );
|
UpdateTimers( Global.iPause != 0 );
|
||||||
DeltaTime = 0.1;
|
DeltaTime = 0.0;
|
||||||
DeltaRenderTime = 0.0;
|
DeltaRenderTime = 0.0;
|
||||||
fSoundTimer = 0.0;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LONGLONG fr, count, oldCount;
|
uint64_t fr, count, oldCount;
|
||||||
|
|
||||||
void UpdateTimers(bool pause) {
|
|
||||||
|
|
||||||
|
void UpdateTimers(bool pause)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
QueryPerformanceFrequency((LARGE_INTEGER *)&fr);
|
QueryPerformanceFrequency((LARGE_INTEGER *)&fr);
|
||||||
QueryPerformanceCounter((LARGE_INTEGER *)&count);
|
QueryPerformanceCounter((LARGE_INTEGER *)&count);
|
||||||
|
#elif __unix__
|
||||||
|
timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
count = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
|
||||||
|
fr = 1000000000;
|
||||||
|
#endif
|
||||||
DeltaRenderTime = double(count - oldCount) / double(fr);
|
DeltaRenderTime = double(count - oldCount) / double(fr);
|
||||||
if (!pause)
|
if (!pause)
|
||||||
{
|
{
|
||||||
@@ -77,15 +76,19 @@ void UpdateTimers(bool pause) {
|
|||||||
|
|
||||||
if (DeltaTime > 1.0)
|
if (DeltaTime > 1.0)
|
||||||
DeltaTime = 1.0;
|
DeltaTime = 1.0;
|
||||||
|
|
||||||
|
fSimulationTime += GetDeltaTime();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DeltaTime = 0.0; // wszystko stoi, bo czas nie płynie
|
DeltaTime = 0.0; // wszystko stoi, bo czas nie płynie
|
||||||
|
|
||||||
oldCount = count;
|
oldCount = count;
|
||||||
// Keep track of the time lapse and frame count
|
// Keep track of the time lapse and frame count
|
||||||
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
#if __unix__
|
||||||
|
double fTime = (double)(count / 1000000000);
|
||||||
|
#elif _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||||
double fTime = ::GetTickCount64() * 0.001f; // Get current time in seconds
|
double fTime = ::GetTickCount64() * 0.001f; // Get current time in seconds
|
||||||
#else
|
#elif _WIN32
|
||||||
double fTime = ::GetTickCount() * 0.001f; // Get current time in seconds
|
double fTime = ::GetTickCount() * 0.001f; // Get current time in seconds
|
||||||
#endif
|
#endif
|
||||||
++dwFrames; // licznik ramek
|
++dwFrames; // licznik ramek
|
||||||
@@ -96,7 +99,6 @@ void UpdateTimers(bool pause) {
|
|||||||
fLastTime = fTime;
|
fLastTime = fTime;
|
||||||
dwFrames = 0L;
|
dwFrames = 0L;
|
||||||
}
|
}
|
||||||
fSimulationTime += DeltaTime;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace timer
|
}; // namespace timer
|
||||||
|
|||||||
16
Timer.h
16
Timer.h
@@ -16,11 +16,7 @@ double GetTime();
|
|||||||
double GetDeltaTime();
|
double GetDeltaTime();
|
||||||
double GetDeltaRenderTime();
|
double GetDeltaRenderTime();
|
||||||
|
|
||||||
void SetDeltaTime(double v);
|
void set_delta_override(double v);
|
||||||
|
|
||||||
bool GetSoundTimer();
|
|
||||||
|
|
||||||
double GetFPS();
|
|
||||||
|
|
||||||
void ResetTimers();
|
void ResetTimers();
|
||||||
|
|
||||||
@@ -35,17 +31,23 @@ public:
|
|||||||
void
|
void
|
||||||
start() {
|
start() {
|
||||||
m_start = std::chrono::steady_clock::now(); }
|
m_start = std::chrono::steady_clock::now(); }
|
||||||
void
|
std::chrono::duration<float, std::milli>
|
||||||
stop() {
|
stop() {
|
||||||
m_accumulator = 0.95f * m_accumulator + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_start ) ).count() / 1000.f; }
|
m_last = std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_start ) );
|
||||||
|
m_accumulator = 0.95f * m_accumulator + m_last.count() / 1000.f;
|
||||||
|
return m_last; }
|
||||||
float
|
float
|
||||||
average() const {
|
average() const {
|
||||||
return m_accumulator / 20.f;}
|
return m_accumulator / 20.f;}
|
||||||
|
std::chrono::microseconds
|
||||||
|
last() const {
|
||||||
|
return m_last; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// members
|
// members
|
||||||
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
|
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
|
||||||
float m_accumulator { 1000.f / 30.f * 20.f }; // 20 last samples, initial 'neutral' rate of 30 fps
|
float m_accumulator { 1000.f / 30.f * 20.f }; // 20 last samples, initial 'neutral' rate of 30 fps
|
||||||
|
std::chrono::microseconds m_last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct subsystem_stopwatches {
|
struct subsystem_stopwatches {
|
||||||
|
|||||||
166
Train.cpp
166
Train.cpp
@@ -381,6 +381,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = {
|
|||||||
{ user_command::generictoggle7, &TTrain::OnCommand_generictoggle },
|
{ user_command::generictoggle7, &TTrain::OnCommand_generictoggle },
|
||||||
{ user_command::generictoggle8, &TTrain::OnCommand_generictoggle },
|
{ user_command::generictoggle8, &TTrain::OnCommand_generictoggle },
|
||||||
{ user_command::generictoggle9, &TTrain::OnCommand_generictoggle },
|
{ user_command::generictoggle9, &TTrain::OnCommand_generictoggle },
|
||||||
|
{ user_command::vehiclemoveforwards, &TTrain::OnCommand_vehiclemoveforwards },
|
||||||
|
{ user_command::vehiclemovebackwards, &TTrain::OnCommand_vehiclemovebackwards },
|
||||||
|
{ user_command::vehicleboost, &TTrain::OnCommand_vehicleboost },
|
||||||
{ user_command::springbraketoggle, &TTrain::OnCommand_springbraketoggle },
|
{ user_command::springbraketoggle, &TTrain::OnCommand_springbraketoggle },
|
||||||
{ user_command::springbrakeenable, &TTrain::OnCommand_springbrakeenable },
|
{ user_command::springbrakeenable, &TTrain::OnCommand_springbrakeenable },
|
||||||
{ user_command::springbrakedisable, &TTrain::OnCommand_springbrakedisable },
|
{ user_command::springbrakedisable, &TTrain::OnCommand_springbrakedisable },
|
||||||
@@ -5582,14 +5585,15 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm
|
|||||||
end::rear ) };
|
end::rear ) };
|
||||||
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ exitdirection ].CouplingFlag, coupling::gangway ) ) {
|
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ exitdirection ].CouplingFlag, coupling::gangway ) ) {
|
||||||
// przejscie do nastepnego pojazdu
|
// przejscie do nastepnego pojazdu
|
||||||
Global.changeDynObj = (
|
auto *targetvehicle = (
|
||||||
exitdirection == end::front ?
|
exitdirection == end::front ?
|
||||||
Train->DynamicObject->PrevConnected() :
|
Train->DynamicObject->PrevConnected() :
|
||||||
Train->DynamicObject->NextConnected() );
|
Train->DynamicObject->NextConnected() );
|
||||||
Global.changeDynObj->MoverParameters->CabOccupied = (
|
targetvehicle->MoverParameters->CabOccupied = (
|
||||||
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
||||||
-1 :
|
-1 :
|
||||||
1 );
|
1 );
|
||||||
|
Train->MoveToVehicle( targetvehicle );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// HACK: match consist door permit state with the preset in the active cab
|
// HACK: match consist door permit state with the preset in the active cab
|
||||||
@@ -5615,14 +5619,15 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com
|
|||||||
end::rear ) };
|
end::rear ) };
|
||||||
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ exitdirection ].CouplingFlag, coupling::gangway ) ) {
|
if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ exitdirection ].CouplingFlag, coupling::gangway ) ) {
|
||||||
// przejscie do nastepnego pojazdu
|
// przejscie do nastepnego pojazdu
|
||||||
Global.changeDynObj = (
|
auto *targetvehicle = (
|
||||||
exitdirection == end::front ?
|
exitdirection == end::front ?
|
||||||
Train->DynamicObject->PrevConnected() :
|
Train->DynamicObject->PrevConnected() :
|
||||||
Train->DynamicObject->NextConnected() );
|
Train->DynamicObject->NextConnected() );
|
||||||
Global.changeDynObj->MoverParameters->CabOccupied = (
|
targetvehicle->MoverParameters->CabOccupied = (
|
||||||
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
||||||
-1 :
|
-1 :
|
||||||
1 );
|
1 );
|
||||||
|
Train->MoveToVehicle( targetvehicle );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// HACK: match consist door permit state with the preset in the active cab
|
// HACK: match consist door permit state with the preset in the active cab
|
||||||
@@ -5632,6 +5637,38 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TTrain::OnCommand_vehiclemoveforwards(TTrain *Train, const command_data &Command) {
|
||||||
|
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Train->DynamicObject->move_set(100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TTrain::OnCommand_vehiclemovebackwards(TTrain *Train, const command_data &Command) {
|
||||||
|
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Train->DynamicObject->move_set(-100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command) {
|
||||||
|
if (Command.action == GLFW_RELEASE || !DebugModeFlag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double boost = Command.param1 != 0.0 ? Command.param1 : 2.78;
|
||||||
|
|
||||||
|
TDynamicObject *d = Train->DynamicObject;
|
||||||
|
while( d ) {
|
||||||
|
d->MoverParameters->V += d->DirectionGet() * boost;
|
||||||
|
d = d->Next(); // pozostałe też
|
||||||
|
}
|
||||||
|
d = Train->DynamicObject->Prev();
|
||||||
|
while( d ) {
|
||||||
|
d->MoverParameters->V += d->DirectionGet() * boost;
|
||||||
|
d = d->Prev(); // w drugą stronę też
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// cab movement update, fixed step part
|
// cab movement update, fixed step part
|
||||||
void TTrain::UpdateCab() {
|
void TTrain::UpdateCab() {
|
||||||
|
|
||||||
@@ -5720,7 +5757,7 @@ bool TTrain::Update( double const Deltatime )
|
|||||||
command_data commanddata;
|
command_data commanddata;
|
||||||
// NOTE: currently we're only storing commands for local vehicle and there's no id system in place,
|
// NOTE: currently we're only storing commands for local vehicle and there's no id system in place,
|
||||||
// so we're supplying 'default' vehicle id of 0
|
// so we're supplying 'default' vehicle id of 0
|
||||||
while( simulation::Commands.pop( commanddata, static_cast<std::size_t>( command_target::vehicle ) | 0 ) ) {
|
while( simulation::Commands.pop( commanddata, static_cast<std::size_t>( command_target::vehicle ) | id() ) ) {
|
||||||
|
|
||||||
auto lookup = m_commandhandlers.find( commanddata.command );
|
auto lookup = m_commandhandlers.find( commanddata.command );
|
||||||
if( lookup != m_commandhandlers.end() ) {
|
if( lookup != m_commandhandlers.end() ) {
|
||||||
@@ -7829,6 +7866,95 @@ void TTrain::DynamicSet(TDynamicObject *d)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
TTrain::MoveToVehicle(TDynamicObject *target) {
|
||||||
|
// > Ra: to nie może być tak robione, to zbytnia proteza jest
|
||||||
|
// indeed, too much hacks...
|
||||||
|
// TODO: cleanup
|
||||||
|
|
||||||
|
TTrain *target_train = simulation::Trains.find(target->name());
|
||||||
|
if (target_train) {
|
||||||
|
// let's try to destroy this TTrain and move to already existing one
|
||||||
|
|
||||||
|
if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) {
|
||||||
|
// tylko jeśli ręcznie prowadzony
|
||||||
|
// jeśli prowadzi AI, to mu nie robimy dywersji!
|
||||||
|
Occupied()->CabDeactivisation();
|
||||||
|
Occupied()->CabOccupied = 0;
|
||||||
|
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
|
||||||
|
Dynamic()->MechInside = false;
|
||||||
|
Dynamic()->Controller = AIdriver;
|
||||||
|
|
||||||
|
Dynamic()->bDisplayCab = false;
|
||||||
|
Dynamic()->ABuSetModelShake( {} );
|
||||||
|
|
||||||
|
Dynamic()->Mechanik->MoveTo(target);
|
||||||
|
|
||||||
|
target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress;
|
||||||
|
target_train->Occupied()->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
|
||||||
|
target_train->Dynamic()->MechInside = true;
|
||||||
|
target_train->Dynamic()->Controller = Humandriver;
|
||||||
|
} else {
|
||||||
|
target_train->Dynamic()->bDisplayCab = false;
|
||||||
|
target_train->Dynamic()->ABuSetModelShake( {} );
|
||||||
|
}
|
||||||
|
|
||||||
|
target_train->Dynamic()->bDisplayCab = true;
|
||||||
|
target_train->Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem?
|
||||||
|
|
||||||
|
// potentially move player
|
||||||
|
if (simulation::Train == this) {
|
||||||
|
simulation::Train = target_train;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete this TTrain
|
||||||
|
pending_delete = true;
|
||||||
|
} else {
|
||||||
|
// move this TTrain to other dynamic
|
||||||
|
|
||||||
|
// remove TTrain from global list, we're going to change dynamic anyway
|
||||||
|
simulation::Trains.detach(Dynamic()->name());
|
||||||
|
|
||||||
|
if (!Dynamic()->Mechanik || !Dynamic()->Mechanik->AIControllFlag) {
|
||||||
|
// tylko jeśli ręcznie prowadzony
|
||||||
|
// jeśli prowadzi AI, to mu nie robimy dywersji!
|
||||||
|
|
||||||
|
Occupied()->CabDeactivisation();
|
||||||
|
Occupied()->CabOccupied = 0;
|
||||||
|
Occupied()->BrakeLevelSet(Occupied()->Handle->GetPos(bh_NP)); //rozwala sterowanie hamulcem GF 04-2016
|
||||||
|
Dynamic()->MechInside = false;
|
||||||
|
Dynamic()->Controller = AIdriver;
|
||||||
|
|
||||||
|
Dynamic()->bDisplayCab = false;
|
||||||
|
Dynamic()->ABuSetModelShake( {} );
|
||||||
|
|
||||||
|
Dynamic()->Mechanik->MoveTo(target);
|
||||||
|
|
||||||
|
DynamicSet(target);
|
||||||
|
|
||||||
|
Occupied()->LimPipePress = Occupied()->PipePress;
|
||||||
|
Occupied()->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
|
||||||
|
Dynamic()->MechInside = true;
|
||||||
|
Dynamic()->Controller = Humandriver;
|
||||||
|
} else {
|
||||||
|
Dynamic()->bDisplayCab = false;
|
||||||
|
Dynamic()->ABuSetModelShake( {} );
|
||||||
|
|
||||||
|
DynamicSet(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeCab(
|
||||||
|
Occupied()->CabActive,
|
||||||
|
Dynamic()->asBaseDir + Occupied()->TypeName + ".mmd" );
|
||||||
|
|
||||||
|
Dynamic()->bDisplayCab = true;
|
||||||
|
Dynamic()->ABuSetModelShake( {} ); // zerowanie przesunięcia przed powrotem?
|
||||||
|
|
||||||
|
// add it back with updated dynamic name
|
||||||
|
simulation::Trains.insert(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// checks whether specified point is within boundaries of the active cab
|
// checks whether specified point is within boundaries of the active cab
|
||||||
bool
|
bool
|
||||||
TTrain::point_inside( Math3D::vector3 const Point ) const {
|
TTrain::point_inside( Math3D::vector3 const Point ) const {
|
||||||
@@ -9106,3 +9232,33 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t TTrain::id() {
|
||||||
|
if (vid == 0) {
|
||||||
|
vid = ++simulation::prev_train_id;
|
||||||
|
WriteLog("net: assigning id " + std::to_string(vid) + " to vehicle " + Dynamic()->name(), logtype::net);
|
||||||
|
}
|
||||||
|
return vid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void train_table::update(double dt)
|
||||||
|
{
|
||||||
|
for (TTrain *train : m_items) {
|
||||||
|
if (!train)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
train->Update(dt);
|
||||||
|
|
||||||
|
if (train->pending_delete) {
|
||||||
|
purge(train->Dynamic()->name());
|
||||||
|
if (simulation::Train == train)
|
||||||
|
simulation::Train = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for single-player destroy non-player trains
|
||||||
|
if (simulation::Train != train
|
||||||
|
&& Global.network_servers.empty() && !Global.network_client) {
|
||||||
|
purge(train->Dynamic()->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
16
Train.h
16
Train.h
@@ -130,6 +130,9 @@ class TTrain {
|
|||||||
bool LoadMMediaFile(std::string const &asFileName);
|
bool LoadMMediaFile(std::string const &asFileName);
|
||||||
dictionary_source *GetTrainState();
|
dictionary_source *GetTrainState();
|
||||||
state_t get_state() const;
|
state_t get_state() const;
|
||||||
|
inline
|
||||||
|
std::string name() const {
|
||||||
|
return Dynamic()->name(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types
|
// types
|
||||||
@@ -384,6 +387,9 @@ class TTrain {
|
|||||||
static void OnCommand_cabchangeforward( TTrain *Train, command_data const &Command );
|
static void OnCommand_cabchangeforward( TTrain *Train, command_data const &Command );
|
||||||
static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command );
|
static void OnCommand_cabchangebackward( TTrain *Train, command_data const &Command );
|
||||||
static void OnCommand_generictoggle( TTrain *Train, command_data const &Command );
|
static void OnCommand_generictoggle( TTrain *Train, command_data const &Command );
|
||||||
|
static void OnCommand_vehiclemoveforwards( TTrain *Train, command_data const &Command );
|
||||||
|
static void OnCommand_vehiclemovebackwards( TTrain *Train, command_data const &Command );
|
||||||
|
static void OnCommand_vehicleboost( TTrain *Train, command_data const &Command );
|
||||||
static void OnCommand_springbraketoggle(TTrain *Train, command_data const &Command);
|
static void OnCommand_springbraketoggle(TTrain *Train, command_data const &Command);
|
||||||
static void OnCommand_springbrakeenable(TTrain *Train, command_data const &Command);
|
static void OnCommand_springbrakeenable(TTrain *Train, command_data const &Command);
|
||||||
static void OnCommand_springbrakedisable(TTrain *Train, command_data const &Command);
|
static void OnCommand_springbrakedisable(TTrain *Train, command_data const &Command);
|
||||||
@@ -754,6 +760,7 @@ private:
|
|||||||
bool m_mastercontrollerinuse { false };
|
bool m_mastercontrollerinuse { false };
|
||||||
float m_mastercontrollerreturndelay { 0.f };
|
float m_mastercontrollerreturndelay { 0.f };
|
||||||
std::vector<std::pair<std::string, texture_handle>> m_screens;
|
std::vector<std::pair<std::string, texture_handle>> m_screens;
|
||||||
|
uint16_t vid { 0 }; // train network recipient id
|
||||||
float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive
|
float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive
|
||||||
double m_brakehandlecp{ 0.0 };
|
double m_brakehandlecp{ 0.0 };
|
||||||
int m_pantselection{ 0 };
|
int m_pantselection{ 0 };
|
||||||
@@ -775,9 +782,18 @@ 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;
|
||||||
|
|
||||||
|
uint16_t id();
|
||||||
|
bool pending_delete = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class train_table : public basic_table<TTrain> {
|
||||||
|
public:
|
||||||
|
void update( double dt );
|
||||||
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ bool TTrackFollower::Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TTrackFollower::Reset()
|
||||||
|
{
|
||||||
|
fCurrentDistance = 0.0;
|
||||||
|
fDirection = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
TTrack * TTrackFollower::SetCurrentTrack(TTrack *pTrack, int end)
|
TTrack * TTrackFollower::SetCurrentTrack(TTrack *pTrack, int end)
|
||||||
{ // przejechanie na inny odcinkek toru, z ewentualnym rozpruciem
|
{ // przejechanie na inny odcinkek toru, z ewentualnym rozpruciem
|
||||||
if (pTrack)
|
if (pTrack)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public:
|
|||||||
//{ return pCurrentSegment->ComputeLength(p1,cp1,cp2,p2); };
|
//{ return pCurrentSegment->ComputeLength(p1,cp1,cp2,p2); };
|
||||||
// inline double GetRadius(double L, double d); //McZapkie-150503
|
// inline double GetRadius(double L, double d); //McZapkie-150503
|
||||||
bool Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir);
|
bool Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir);
|
||||||
|
void Reset();
|
||||||
void Render(float fNr);
|
void Render(float fNr);
|
||||||
// members
|
// members
|
||||||
double fOffsetH = 0.0; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania
|
double fOffsetH = 0.0; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania
|
||||||
|
|||||||
247
application.cpp
247
application.cpp
@@ -43,6 +43,11 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#pragma comment (lib, "dbghelp.lib")
|
#pragma comment (lib, "dbghelp.lib")
|
||||||
#pragma comment (lib, "version.lib")
|
#pragma comment (lib, "version.lib")
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" { _declspec( dllexport ) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; }
|
extern "C" { _declspec( dllexport ) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; }
|
||||||
extern "C" { _declspec( dllexport ) DWORD NvOptimusEnablement = 0x00000001; }
|
extern "C" { _declspec( dllexport ) DWORD NvOptimusEnablement = 0x00000001; }
|
||||||
|
|
||||||
@@ -65,11 +70,7 @@ extern WNDPROC BaseWindowProc;
|
|||||||
// user input callbacks
|
// user input callbacks
|
||||||
|
|
||||||
void focus_callback( GLFWwindow *window, int focus ) {
|
void focus_callback( GLFWwindow *window, int focus ) {
|
||||||
if( Global.bInactivePause ) // jeśli ma być pauzowanie okna w tle
|
Application.on_focus_change(focus != 0);
|
||||||
if( focus )
|
|
||||||
Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie
|
|
||||||
else
|
|
||||||
Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
||||||
@@ -77,7 +78,6 @@ void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
|||||||
// TBD, TODO: merge them?
|
// TBD, TODO: merge them?
|
||||||
Global.iWindowWidth = w;
|
Global.iWindowWidth = w;
|
||||||
Global.iWindowHeight = h;
|
Global.iWindowHeight = h;
|
||||||
Global.fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use
|
|
||||||
glViewport( 0, 0, w, h );
|
glViewport( 0, 0, w, h );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +101,11 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo
|
|||||||
Application.on_key( key, scancode, action, mods );
|
Application.on_key( key, scancode, action, mods );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void char_callback(GLFWwindow *window, unsigned int c)
|
||||||
|
{
|
||||||
|
Application.on_char(c);
|
||||||
|
}
|
||||||
|
|
||||||
// public:
|
// public:
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -140,9 +145,28 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!init_network())
|
||||||
|
return -1;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double eu07_application::generate_sync() {
|
||||||
|
if (Timer::GetDeltaTime() == 0.0)
|
||||||
|
return 0.0;
|
||||||
|
double sync = 0.0;
|
||||||
|
for (const TDynamicObject* vehicle : simulation::Vehicles.sequence()) {
|
||||||
|
auto const pos { vehicle->GetPosition() };
|
||||||
|
sync += pos.x + pos.y + pos.z;
|
||||||
|
}
|
||||||
|
sync += Random(1.0, 100.0);
|
||||||
|
return sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eu07_application::queue_quit() {
|
||||||
|
glfwSetWindowShouldClose(m_windows[0], GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
eu07_application::run() {
|
eu07_application::run() {
|
||||||
|
|
||||||
@@ -151,11 +175,125 @@ eu07_application::run() {
|
|||||||
{
|
{
|
||||||
Timer::subsystem.mainloop_total.start();
|
Timer::subsystem.mainloop_total.start();
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// multiplayer command relaying logic can seem a bit complex
|
||||||
|
//
|
||||||
|
// we are simultaneously:
|
||||||
|
// => master (not client) OR slave (client)
|
||||||
|
// => server OR not
|
||||||
|
//
|
||||||
|
// trivia: being client and server is possible
|
||||||
|
|
||||||
|
double frameStartTime = Timer::GetTime();
|
||||||
|
|
||||||
|
if (m_modes[m_modestack.top()]->is_command_processor()) {
|
||||||
|
// active mode is doing real calculations (e.g. drivermode)
|
||||||
|
int loop_remaining = MAX_NETWORK_PER_FRAME;
|
||||||
|
while (--loop_remaining > 0)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
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();
|
||||||
|
|
||||||
|
// push these into local queue
|
||||||
|
add_to_dequemap(local_commands, remote_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(MAX_NETWORK_PER_FRAME - loop_remaining);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
loop_remaining = -1;
|
||||||
|
}
|
||||||
|
// if we're master
|
||||||
|
else {
|
||||||
|
// just push local commands to execution
|
||||||
|
add_to_dequemap(commands_to_exec, local_commands);
|
||||||
|
|
||||||
|
loop_remaining = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send commands to command queue
|
||||||
|
simulation::Commands.push_commands(commands_to_exec);
|
||||||
|
|
||||||
|
// do actual frame processing
|
||||||
if (!m_modes[ m_modestack.top() ]->update())
|
if (!m_modes[ m_modestack.top() ]->update())
|
||||||
break;
|
return 0;
|
||||||
|
|
||||||
|
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();
|
||||||
|
double render = Timer::GetDeltaRenderTime();
|
||||||
|
m_network->servers->push_delta(render, delta, sync, commands_to_exec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're slave
|
||||||
|
if (m_network && m_network->client)
|
||||||
|
{
|
||||||
|
// verify sync
|
||||||
|
if (sync != slave_sync) {
|
||||||
|
WriteLog("net: desync! calculated: " + std::to_string(sync)
|
||||||
|
+ ", received: " + std::to_string(slave_sync), logtype::net);
|
||||||
|
|
||||||
|
Global.desync = slave_sync - sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set total delta for rendering code
|
||||||
|
double totalDelta = Timer::GetTime() - frameStartTime;
|
||||||
|
Timer::set_delta_override(totalDelta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loop_remaining) {
|
||||||
|
// loop break forced by counter
|
||||||
|
float received = m_network->client->get_frame_counter();
|
||||||
|
float awaiting = m_network->client->get_awaiting_frames();
|
||||||
|
|
||||||
|
// TODO: don't meddle with mode progresbar
|
||||||
|
m_modes[m_modestack.top()]->set_progress(100.0f, 100.0f * (received - awaiting) / received);
|
||||||
|
} else {
|
||||||
|
m_modes[m_modestack.top()]->set_progress(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
} 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())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
// TODO: re-enable after python changes merge
|
||||||
|
// m_taskqueue.update();
|
||||||
|
|
||||||
if (!GfxRenderer->Render())
|
if (!GfxRenderer->Render())
|
||||||
break;
|
return 0;
|
||||||
|
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
@@ -164,7 +302,12 @@ eu07_application::run() {
|
|||||||
|
|
||||||
m_modes[ m_modestack.top() ]->on_event_poll();
|
m_modes[ m_modestack.top() ]->on_event_poll();
|
||||||
|
|
||||||
Timer::subsystem.mainloop_total.stop();
|
if (m_network)
|
||||||
|
m_network->update();
|
||||||
|
|
||||||
|
auto frametime = Timer::subsystem.mainloop_total.stop();
|
||||||
|
if (Global.minframetime.count() != 0.0f && (Global.minframetime - frametime).count() > 0.0f)
|
||||||
|
std::this_thread::sleep_for(Global.minframetime - frametime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -199,8 +342,12 @@ eu07_application::release_python_lock() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
eu07_application::exit() {
|
eu07_application::exit() {
|
||||||
|
for (auto &mode : m_modes)
|
||||||
|
mode.reset();
|
||||||
|
|
||||||
SafeDelete( simulation::Train );
|
m_network.reset();
|
||||||
|
|
||||||
|
// SafeDelete( simulation::Train );
|
||||||
SafeDelete( simulation::Region );
|
SafeDelete( simulation::Region );
|
||||||
|
|
||||||
ui_layer::shutdown();
|
ui_layer::shutdown();
|
||||||
@@ -208,8 +355,11 @@ eu07_application::exit() {
|
|||||||
for( auto *window : m_windows ) {
|
for( auto *window : m_windows ) {
|
||||||
glfwDestroyWindow( window );
|
glfwDestroyWindow( window );
|
||||||
}
|
}
|
||||||
glfwTerminate();
|
|
||||||
m_taskqueue.exit();
|
m_taskqueue.exit();
|
||||||
|
glfwTerminate();
|
||||||
|
|
||||||
|
if (!Global.exec_on_exit.empty())
|
||||||
|
system(Global.exec_on_exit.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -222,7 +372,6 @@ eu07_application::render_ui() {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
eu07_application::pop_mode() {
|
eu07_application::pop_mode() {
|
||||||
|
|
||||||
if( m_modestack.empty() ) { return false; }
|
if( m_modestack.empty() ) { return false; }
|
||||||
|
|
||||||
m_modes[ m_modestack.top() ]->exit();
|
m_modes[ m_modestack.top() ]->exit();
|
||||||
@@ -291,6 +440,7 @@ eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const {
|
|||||||
glfwGetCursorPos( m_windows.front(), &Horizontal, &Vertical );
|
glfwGetCursorPos( m_windows.front(), &Horizontal, &Vertical );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
eu07_application::get_mouse_button( int const Button ) const {
|
eu07_application::get_mouse_button( int const Button ) const {
|
||||||
|
|
||||||
@@ -314,6 +464,13 @@ eu07_application::on_key( int const Key, int const Scancode, int const Action, i
|
|||||||
m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods );
|
m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eu07_application::on_char( unsigned int const Char ) {
|
||||||
|
|
||||||
|
if( m_modestack.empty() ) { return; }
|
||||||
|
|
||||||
|
m_modes[ m_modestack.top() ]->on_char( Char );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
eu07_application::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
eu07_application::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||||
|
|
||||||
@@ -338,6 +495,13 @@ eu07_application::on_scroll( double const Xoffset, double const Yoffset ) {
|
|||||||
m_modes[ m_modestack.top() ]->on_scroll( Xoffset, Yoffset );
|
m_modes[ m_modestack.top() ]->on_scroll( Xoffset, Yoffset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eu07_application::on_focus_change(bool focus) {
|
||||||
|
if( Global.bInactivePause && !m_network->client) {// jeśli ma być pauzowanie okna w tle
|
||||||
|
command_relay relay;
|
||||||
|
relay.post(user_command::focuspauseset, focus ? 1.0 : 0.0, 0.0, GLFW_PRESS, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GLFWwindow *
|
GLFWwindow *
|
||||||
eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership , bool share_ctx) {
|
eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership , bool share_ctx) {
|
||||||
|
|
||||||
@@ -394,17 +558,21 @@ std::string eu07_application::describe_monitor(GLFWmonitor *monitor) const {
|
|||||||
return name + ":" + std::to_string(x) + "," + std::to_string(y);
|
return name + ":" + std::to_string(x) + "," + std::to_string(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private:
|
||||||
|
|
||||||
void
|
void
|
||||||
eu07_application::init_debug() {
|
eu07_application::init_debug() {
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined (_DEBUG)
|
#if defined(_MSC_VER) && defined (_DEBUG)
|
||||||
// memory leaks
|
// memory leaks
|
||||||
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
|
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
|
||||||
|
/*
|
||||||
// floating point operation errors
|
// floating point operation errors
|
||||||
auto state { _clearfp() };
|
auto state { _clearfp() };
|
||||||
state = _control87( 0, 0 );
|
state = _control87( 0, 0 );
|
||||||
// this will turn on FPE for #IND and zerodiv
|
// this will turn on FPE for #IND and zerodiv
|
||||||
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
|
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
::SetUnhandledExceptionFilter( unhandled_handler );
|
::SetUnhandledExceptionFilter( unhandled_handler );
|
||||||
@@ -417,7 +585,11 @@ eu07_application::init_files() {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DeleteFile( "log.txt" );
|
DeleteFile( "log.txt" );
|
||||||
DeleteFile( "errors.txt" );
|
DeleteFile( "errors.txt" );
|
||||||
_mkdir( "logs" );
|
CreateDirectory( "logs", NULL );
|
||||||
|
#elif __unix__
|
||||||
|
unlink("log.txt");
|
||||||
|
unlink("errors.txt");
|
||||||
|
mkdir("logs", 0755);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,10 +597,12 @@ int
|
|||||||
eu07_application::init_settings( int Argc, char *Argv[] ) {
|
eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||||
|
|
||||||
Global.LoadIniFile( "eu07.ini" );
|
Global.LoadIniFile( "eu07.ini" );
|
||||||
|
#ifdef _WIN32
|
||||||
if( ( Global.iWriteLogEnabled & 2 ) != 0 ) {
|
if( ( Global.iWriteLogEnabled & 2 ) != 0 ) {
|
||||||
// show output console if requested
|
// show output console if requested
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' );
|
std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' );
|
||||||
Global.ExecutableName =
|
Global.ExecutableName =
|
||||||
@@ -486,7 +660,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 {
|
||||||
@@ -588,6 +762,7 @@ eu07_application::init_callbacks() {
|
|||||||
glfwSetMouseButtonCallback( window, mouse_button_callback );
|
glfwSetMouseButtonCallback( window, mouse_button_callback );
|
||||||
glfwSetKeyCallback( window, key_callback );
|
glfwSetKeyCallback( window, key_callback );
|
||||||
glfwSetScrollCallback( window, scroll_callback );
|
glfwSetScrollCallback( window, scroll_callback );
|
||||||
|
glfwSetCharCallback(window, char_callback);
|
||||||
glfwSetWindowFocusCallback( window, focus_callback );
|
glfwSetWindowFocusCallback( window, focus_callback );
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
@@ -668,7 +843,12 @@ eu07_application::init_data() {
|
|||||||
|
|
||||||
int
|
int
|
||||||
eu07_application::init_modes() {
|
eu07_application::init_modes() {
|
||||||
|
Global.local_random_engine.seed(std::random_device{}());
|
||||||
|
|
||||||
|
if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty()) {
|
||||||
|
ErrorLog("launcher mode is currently not supported in network mode");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// NOTE: we could delay creation/initialization until transition to specific mode is requested,
|
// NOTE: we could delay creation/initialization until transition to specific mode is requested,
|
||||||
// but doing it in one go at the start saves us some error checking headache down the road
|
// but doing it in one go at the start saves us some error checking headache down the road
|
||||||
|
|
||||||
@@ -687,3 +867,42 @@ eu07_application::init_modes() {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool eu07_application::init_network() {
|
||||||
|
if (!Global.network_servers.empty() || Global.network_client) {
|
||||||
|
// create network manager
|
||||||
|
m_network.emplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const &pair : Global.network_servers) {
|
||||||
|
// create all servers
|
||||||
|
m_network->create_server(pair.first, pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Global.network_client) {
|
||||||
|
// create client
|
||||||
|
m_network->connect(Global.network_client->first, Global.network_client->second);
|
||||||
|
} else {
|
||||||
|
// we're simulation master
|
||||||
|
if (!Global.random_seed)
|
||||||
|
Global.random_seed = std::random_device{}();
|
||||||
|
Global.random_engine.seed(Global.random_seed);
|
||||||
|
|
||||||
|
// TODO: sort out this timezone mess
|
||||||
|
std::time_t utc_now = std::time(nullptr);
|
||||||
|
|
||||||
|
tm tm_local, tm_utc;
|
||||||
|
tm *tmp = std::localtime(&utc_now);
|
||||||
|
memcpy(&tm_local, tmp, sizeof(tm));
|
||||||
|
tmp = std::gmtime(&utc_now);
|
||||||
|
memcpy(&tm_utc, tmp, sizeof(tm));
|
||||||
|
|
||||||
|
int64_t offset = (tm_local.tm_hour * 3600 + tm_local.tm_min * 60 + tm_local.tm_sec)
|
||||||
|
- (tm_utc.tm_hour * 3600 + tm_utc.tm_min * 60 + tm_utc.tm_sec);
|
||||||
|
|
||||||
|
Global.starting_timestamp = utc_now + offset;
|
||||||
|
Global.ready_to_load = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
#include "applicationmode.h"
|
#include "applicationmode.h"
|
||||||
#include "PyInt.h"
|
#include "PyInt.h"
|
||||||
|
#include "network/manager.h"
|
||||||
|
|
||||||
class eu07_application {
|
class eu07_application {
|
||||||
|
const int MAX_NETWORK_PER_FRAME = 1000;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// types
|
// types
|
||||||
@@ -72,15 +74,24 @@ public:
|
|||||||
// input handlers
|
// input handlers
|
||||||
void
|
void
|
||||||
on_key( int const Key, int const Scancode, int const Action, int const Mods );
|
on_key( int const Key, int const Scancode, int const Action, int const Mods );
|
||||||
|
void
|
||||||
|
on_char( unsigned int const Char );
|
||||||
void
|
void
|
||||||
on_cursor_pos( double const Horizontal, double const Vertical );
|
on_cursor_pos( double const Horizontal, double const Vertical );
|
||||||
void
|
void
|
||||||
on_mouse_button( int const Button, int const Action, int const Mods );
|
on_mouse_button( int const Button, int const Action, int const Mods );
|
||||||
void
|
void
|
||||||
on_scroll( double const Xoffset, double const Yoffset );
|
on_scroll( double const Xoffset, double const Yoffset );
|
||||||
|
void
|
||||||
|
on_focus_change(bool focus);
|
||||||
// gives access to specified window, creates a new window if index == -1
|
// gives access to specified window, creates a new window if index == -1
|
||||||
GLFWwindow *
|
GLFWwindow *
|
||||||
window( int const Windowindex = 0, bool visible = false, int width = 1, int height = 1, GLFWmonitor *monitor = nullptr, bool keep_ownership = true, bool share_ctx = true );
|
window( int const Windowindex = 0, bool visible = false, int width = 1, int height = 1, GLFWmonitor *monitor = nullptr, bool keep_ownership = true, bool share_ctx = true );
|
||||||
|
// generate network sync verification number
|
||||||
|
double
|
||||||
|
generate_sync();
|
||||||
|
void
|
||||||
|
queue_quit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types
|
// types
|
||||||
@@ -97,6 +108,7 @@ private:
|
|||||||
int init_audio();
|
int init_audio();
|
||||||
int init_data();
|
int init_data();
|
||||||
int init_modes();
|
int init_modes();
|
||||||
|
bool init_network();
|
||||||
GLFWmonitor * find_monitor( const std::string &str ) const;
|
GLFWmonitor * find_monitor( const std::string &str ) const;
|
||||||
std::string describe_monitor( GLFWmonitor *monitor ) const;
|
std::string describe_monitor( GLFWmonitor *monitor ) const;
|
||||||
// members
|
// members
|
||||||
@@ -104,6 +116,8 @@ private:
|
|||||||
mode_stack m_modestack; // current behaviour mode
|
mode_stack m_modestack; // current behaviour mode
|
||||||
python_taskqueue m_taskqueue;
|
python_taskqueue m_taskqueue;
|
||||||
std::vector<GLFWwindow *> m_windows;
|
std::vector<GLFWwindow *> m_windows;
|
||||||
|
|
||||||
|
std::optional<network::manager> m_network;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern eu07_application Application;
|
extern eu07_application Application;
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ public:
|
|||||||
void
|
void
|
||||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) = 0;
|
on_key( int const Key, int const Scancode, int const Action, int const Mods ) = 0;
|
||||||
virtual
|
virtual
|
||||||
|
void
|
||||||
|
on_char( unsigned int const Char ) = 0;
|
||||||
|
virtual
|
||||||
void
|
void
|
||||||
on_cursor_pos( double const X, double const Y ) = 0;
|
on_cursor_pos( double const X, double const Y ) = 0;
|
||||||
virtual
|
virtual
|
||||||
@@ -68,6 +71,9 @@ public:
|
|||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_event_poll() = 0;
|
on_event_poll() = 0;
|
||||||
|
virtual
|
||||||
|
bool
|
||||||
|
is_command_processor() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// members
|
// members
|
||||||
|
|||||||
124
command.cpp
124
command.cpp
@@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
#include "simulation.h"
|
||||||
|
#include "Train.h"
|
||||||
|
|
||||||
namespace simulation {
|
namespace simulation {
|
||||||
|
|
||||||
@@ -266,7 +268,36 @@ commanddescription_sequence Commands_descriptions = {
|
|||||||
{ "speedcontrolbutton6", command_target::vehicle },
|
{ "speedcontrolbutton6", command_target::vehicle },
|
||||||
{ "speedcontrolbutton7", command_target::vehicle },
|
{ "speedcontrolbutton7", command_target::vehicle },
|
||||||
{ "speedcontrolbutton8", command_target::vehicle },
|
{ "speedcontrolbutton8", command_target::vehicle },
|
||||||
{ "speedcontrolbutton9", command_target::vehicle }
|
{ "speedcontrolbutton9", command_target::vehicle },
|
||||||
|
|
||||||
|
{ "globalradiostop", command_target::simulation },
|
||||||
|
{ "timejump", command_target::simulation },
|
||||||
|
{ "timejumplarge", command_target::simulation },
|
||||||
|
{ "timejumpsmall", command_target::simulation },
|
||||||
|
{ "setdatetime", command_target::simulation },
|
||||||
|
{ "setweather", command_target::simulation },
|
||||||
|
{ "settemperature", command_target::simulation },
|
||||||
|
{ "vehiclemoveforwards", command_target::vehicle },
|
||||||
|
{ "vehiclemovebackwards", command_target::vehicle },
|
||||||
|
{ "vehicleboost", command_target::vehicle },
|
||||||
|
{ "debugtoggle", command_target::simulation },
|
||||||
|
{ "focuspauseset", command_target::simulation },
|
||||||
|
{ "pausetoggle", command_target::simulation },
|
||||||
|
{ "entervehicle", command_target::simulation },
|
||||||
|
{ "resetconsist", command_target::simulation },
|
||||||
|
{ "fillcompressor", command_target::simulation },
|
||||||
|
{ "consistreleaser", command_target::simulation },
|
||||||
|
{ "queueevent", command_target::simulation },
|
||||||
|
{ "setlight", command_target::simulation },
|
||||||
|
{ "insertmodel", command_target::simulation },
|
||||||
|
{ "deletemodel", command_target::simulation },
|
||||||
|
{ "trainsetmove", command_target::simulation },
|
||||||
|
{ "consistteleport", command_target::simulation },
|
||||||
|
{ "pullalarmchain", command_target::simulation },
|
||||||
|
{ "sendaicommand", command_target::simulation },
|
||||||
|
{ "spawntrainset", command_target::simulation },
|
||||||
|
{ "destroytrainset", command_target::simulation },
|
||||||
|
{ "quitsimulation", command_target::simulation },
|
||||||
};
|
};
|
||||||
|
|
||||||
} // simulation
|
} // simulation
|
||||||
@@ -274,10 +305,18 @@ commanddescription_sequence Commands_descriptions = {
|
|||||||
// posts specified command for specified recipient
|
// posts specified command for specified recipient
|
||||||
void
|
void
|
||||||
command_queue::push( command_data const &Command, std::size_t const Recipient ) {
|
command_queue::push( command_data const &Command, std::size_t const Recipient ) {
|
||||||
|
if (is_network_target(Recipient)) {
|
||||||
|
auto lookup = m_intercept_queue.emplace(Recipient, commanddata_sequence());
|
||||||
|
lookup.first->second.emplace_back(Command);
|
||||||
|
} else {
|
||||||
|
push_direct(Command, Recipient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_queue::push_direct(const command_data &Command, const uint32_t Recipient) {
|
||||||
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
|
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
|
||||||
// recipient stack was either located or created, so we can add to it quite safely
|
// recipient stack was either located or created, so we can add to it quite safely
|
||||||
lookup.first->second.emplace( Command );
|
lookup.first->second.emplace_back( Command );
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
||||||
@@ -296,15 +335,45 @@ command_queue::pop( command_data &Command, std::size_t const Recipient ) {
|
|||||||
}
|
}
|
||||||
// we have command stack with command(s) on it, retrieve and pop the first one
|
// we have command stack with command(s) on it, retrieve and pop the first one
|
||||||
Command = commands.front();
|
Command = commands.front();
|
||||||
commands.pop();
|
commands.pop_front();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool command_queue::is_network_target(uint32_t const Recipient) {
|
||||||
|
const command_target target = (command_target)(Recipient & ~0xffff);
|
||||||
|
|
||||||
|
if (target == command_target::entity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_queue::commands_map command_queue::pop_intercept_queue() {
|
||||||
|
commands_map map(m_intercept_queue);
|
||||||
|
m_intercept_queue.clear();
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_queue::push_commands(const commands_map &commands) {
|
||||||
|
for (auto const &kv : commands)
|
||||||
|
for (command_data const &data : kv.second)
|
||||||
|
push_direct(data, kv.first);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
command_relay::post( user_command const Command, double const Param1, double const Param2, int const Action, std::uint16_t const Recipient ) const {
|
command_relay::post(user_command const Command, double const Param1, double const Param2,
|
||||||
|
int const Action, uint16_t Recipient, glm::vec3 Position, const std::string *Payload) const {
|
||||||
|
|
||||||
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
|
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
|
||||||
|
|
||||||
|
if (command.target == command_target::vehicle && Recipient == 0) {
|
||||||
|
// default 0 recipient is currently controlled train
|
||||||
|
if (simulation::Train == nullptr)
|
||||||
|
return;
|
||||||
|
Recipient = simulation::Train->id();
|
||||||
|
}
|
||||||
|
|
||||||
if( ( command.target == command_target::vehicle )
|
if( ( command.target == command_target::vehicle )
|
||||||
&& ( true == FreeFlyModeFlag )
|
&& ( true == FreeFlyModeFlag )
|
||||||
&& ( ( false == DebugModeFlag )
|
&& ( ( false == DebugModeFlag )
|
||||||
@@ -313,44 +382,15 @@ command_relay::post( user_command const Command, double const Param1, double con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
simulation::Commands.push(
|
if (Position == glm::vec3(0.0f))
|
||||||
command_data{
|
Position = Global.pCamera.Pos;
|
||||||
Command,
|
|
||||||
Action,
|
uint32_t combined_recipient = static_cast<uint32_t>( command.target ) | Recipient;
|
||||||
Param1,
|
command_data commanddata({Command, Action, Param1, Param2, Timer::GetDeltaTime(), FreeFlyModeFlag, Position });
|
||||||
Param2,
|
if (Payload)
|
||||||
Timer::GetDeltaTime() },
|
commanddata.payload = *Payload;
|
||||||
static_cast<std::size_t>( command.target ) | Recipient );
|
|
||||||
/*
|
simulation::Commands.push(commanddata, combined_recipient);
|
||||||
#ifdef _DEBUG
|
|
||||||
if( Action != GLFW_RELEASE ) {
|
|
||||||
// key was pressed or is still held
|
|
||||||
if( false == command.name.empty() ) {
|
|
||||||
if( false == (
|
|
||||||
( Command == user_command::moveleft )
|
|
||||||
|| ( Command == user_command::moveleftfast )
|
|
||||||
|| ( Command == user_command::moveright )
|
|
||||||
|| ( Command == user_command::moverightfast )
|
|
||||||
|| ( Command == user_command::moveforward )
|
|
||||||
|| ( Command == user_command::moveforwardfast )
|
|
||||||
|| ( Command == user_command::moveback )
|
|
||||||
|| ( Command == user_command::movebackfast )
|
|
||||||
|| ( Command == user_command::moveup )
|
|
||||||
|| ( Command == user_command::moveupfast )
|
|
||||||
|| ( Command == user_command::movedown )
|
|
||||||
|| ( Command == user_command::movedownfast )
|
|
||||||
|| ( Command == user_command::movevector )
|
|
||||||
|| ( Command == user_command::viewturn ) ) ) {
|
|
||||||
WriteLog( "Command issued: " + command.name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// key was released (but we don't log this)
|
|
||||||
WriteLog( "Key released: " + command.name );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
73
command.h
73
command.h
@@ -260,13 +260,42 @@ enum class user_command {
|
|||||||
speedcontrolbutton7,
|
speedcontrolbutton7,
|
||||||
speedcontrolbutton8,
|
speedcontrolbutton8,
|
||||||
speedcontrolbutton9,
|
speedcontrolbutton9,
|
||||||
|
|
||||||
|
globalradiostop,
|
||||||
|
timejump,
|
||||||
|
timejumplarge,
|
||||||
|
timejumpsmall,
|
||||||
|
setdatetime,
|
||||||
|
setweather,
|
||||||
|
settemperature,
|
||||||
|
vehiclemoveforwards,
|
||||||
|
vehiclemovebackwards,
|
||||||
|
vehicleboost,
|
||||||
|
debugtoggle,
|
||||||
|
focuspauseset,
|
||||||
|
pausetoggle,
|
||||||
|
entervehicle,
|
||||||
|
resetconsist,
|
||||||
|
fillcompressor,
|
||||||
|
consistreleaser,
|
||||||
|
queueevent,
|
||||||
|
setlight,
|
||||||
|
insertmodel,
|
||||||
|
deletemodel,
|
||||||
|
dynamicmove,
|
||||||
|
consistteleport,
|
||||||
|
pullalarmchain,
|
||||||
|
sendaicommand,
|
||||||
|
spawntrainset,
|
||||||
|
destroytrainset,
|
||||||
|
quitsimulation,
|
||||||
|
|
||||||
none = -1
|
none = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class command_target {
|
enum class command_target {
|
||||||
|
|
||||||
userinterface,
|
userinterface,
|
||||||
simulation,
|
|
||||||
/*
|
/*
|
||||||
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
|
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
|
||||||
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
|
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
|
||||||
@@ -276,7 +305,9 @@ enum class command_target {
|
|||||||
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
|
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
|
||||||
vehicle = 0x10000,
|
vehicle = 0x10000,
|
||||||
signal = 0x20000,
|
signal = 0x20000,
|
||||||
entity = 0x40000
|
entity = 0x40000,
|
||||||
|
|
||||||
|
simulation = 0x80000
|
||||||
};
|
};
|
||||||
|
|
||||||
struct command_description {
|
struct command_description {
|
||||||
@@ -292,6 +323,11 @@ struct command_data {
|
|||||||
double param1;
|
double param1;
|
||||||
double param2;
|
double param2;
|
||||||
double time_delta;
|
double time_delta;
|
||||||
|
|
||||||
|
bool freefly;
|
||||||
|
glm::vec3 location;
|
||||||
|
|
||||||
|
std::string payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
|
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
|
||||||
@@ -301,6 +337,9 @@ struct command_data {
|
|||||||
class command_queue {
|
class command_queue {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// types
|
||||||
|
typedef std::deque<command_data> commanddata_sequence;
|
||||||
|
typedef std::unordered_map<uint32_t, commanddata_sequence> commands_map;
|
||||||
// methods
|
// methods
|
||||||
// posts specified command for specified recipient
|
// posts specified command for specified recipient
|
||||||
void
|
void
|
||||||
@@ -308,16 +347,36 @@ public:
|
|||||||
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
||||||
bool
|
bool
|
||||||
pop( command_data &Command, std::size_t const Recipient );
|
pop( command_data &Command, std::size_t const Recipient );
|
||||||
|
// checks if given command must be scheduled on server
|
||||||
|
bool
|
||||||
|
is_network_target(const uint32_t Recipient);
|
||||||
|
|
||||||
|
// pops commands from intercept queue
|
||||||
|
commands_map pop_intercept_queue();
|
||||||
|
|
||||||
|
// pushes commands into main queue
|
||||||
|
void push_commands(const commands_map &commands);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// types
|
|
||||||
typedef std::queue<command_data> commanddata_sequence;
|
|
||||||
typedef std::unordered_map<std::size_t, commanddata_sequence> commanddatasequence_map;
|
|
||||||
// members
|
// members
|
||||||
commanddatasequence_map m_commands;
|
// contains command ready to execution
|
||||||
|
commands_map m_commands;
|
||||||
|
|
||||||
|
// contains intercepted commands to be read by application layer
|
||||||
|
commands_map m_intercept_queue;
|
||||||
|
|
||||||
|
void push_direct( command_data const &Command, uint32_t const Recipient );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename A, typename B>
|
||||||
|
void add_to_dequemap(std::unordered_map<A, std::deque<B>> &lhs, const std::unordered_map<A, std::deque<B>> &rhs) {
|
||||||
|
for (auto const &kv : rhs) {
|
||||||
|
auto lookup = lhs.emplace(kv.first, std::deque<B>());
|
||||||
|
for (B const &data : kv.second)
|
||||||
|
lookup.first->second.emplace_back(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
|
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
|
||||||
// but realistically it's not like we're going to run more than one simulation at a time
|
// but realistically it's not like we're going to run more than one simulation at a time
|
||||||
namespace simulation {
|
namespace simulation {
|
||||||
@@ -341,7 +400,7 @@ public:
|
|||||||
// TODO: replace uint16_t with recipient handle, based on item id
|
// TODO: replace uint16_t with recipient handle, based on item id
|
||||||
void
|
void
|
||||||
post(user_command const Command, double const Param1, double const Param2,
|
post(user_command const Command, double const Param1, double const Param2,
|
||||||
int const Action, std::uint16_t const Recipient ) const;
|
int const Action, uint16_t Recipient, glm::vec3 Position = glm::vec3(0.0f) , const std::string *Payload = nullptr) const;
|
||||||
private:
|
private:
|
||||||
// types
|
// types
|
||||||
// members
|
// members
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ driverkeyboard_input::default_bindings() {
|
|||||||
// batterydisable,
|
// batterydisable,
|
||||||
{ user_command::motorblowerstogglefront, GLFW_KEY_N | keymodifier::shift },
|
{ user_command::motorblowerstogglefront, GLFW_KEY_N | keymodifier::shift },
|
||||||
{ user_command::motorblowerstogglerear, GLFW_KEY_M | keymodifier::shift },
|
{ user_command::motorblowerstogglerear, GLFW_KEY_M | keymodifier::shift },
|
||||||
{ user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control }
|
{ user_command::motorblowersdisableall, GLFW_KEY_M | keymodifier::control },
|
||||||
// coolingfanstoggle,
|
// coolingfanstoggle,
|
||||||
// tempomattoggle,
|
// tempomattoggle,
|
||||||
// springbraketoggle,
|
// springbraketoggle,
|
||||||
@@ -269,6 +269,15 @@ driverkeyboard_input::default_bindings() {
|
|||||||
// speedcontrolbutton7,
|
// speedcontrolbutton7,
|
||||||
// speedcontrolbutton8,
|
// speedcontrolbutton8,
|
||||||
// speedcontrolbutton9,
|
// speedcontrolbutton9,
|
||||||
|
// admin_timejump,
|
||||||
|
{ user_command::timejumplarge, GLFW_KEY_F1 | keymodifier::control },
|
||||||
|
{ user_command::timejumpsmall, GLFW_KEY_F1 | keymodifier::shift },
|
||||||
|
// admin_vehiclemove,
|
||||||
|
{ user_command::vehiclemoveforwards, GLFW_KEY_LEFT_BRACKET | keymodifier::control },
|
||||||
|
{ user_command::vehiclemovebackwards, GLFW_KEY_RIGHT_BRACKET | keymodifier::control },
|
||||||
|
{ user_command::vehicleboost, GLFW_KEY_TAB | keymodifier::control },
|
||||||
|
{ user_command::debugtoggle, GLFW_KEY_F12 | keymodifier::control | keymodifier::shift },
|
||||||
|
{ user_command::pausetoggle, GLFW_KEY_ESCAPE }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
174
drivermode.cpp
174
drivermode.cpp
@@ -226,11 +226,26 @@ driver_mode::update() {
|
|||||||
|
|
||||||
// variable step simulation time routines
|
// variable step simulation time routines
|
||||||
|
|
||||||
|
if (!change_train.empty()) {
|
||||||
|
TTrain *train = simulation::Trains.find(change_train);
|
||||||
|
if (train) {
|
||||||
|
simulation::Train = train;
|
||||||
|
InOutKey();
|
||||||
|
m_relay.post(user_command::aidriverdisable, 0.0, 0.0, GLFW_PRESS, 0);
|
||||||
|
change_train.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
if( ( simulation::Train == nullptr ) && ( false == FreeFlyModeFlag ) ) {
|
||||||
// intercept cases when the driven train got removed after entering portal
|
// intercept cases when the driven train got removed after entering portal
|
||||||
InOutKey();
|
InOutKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!FreeFlyModeFlag && simulation::Train->Dynamic() != Camera.m_owner) {
|
||||||
|
// fixup camera after vehicle switch
|
||||||
|
CabView();
|
||||||
|
}
|
||||||
|
/*
|
||||||
if( Global.changeDynObj ) {
|
if( Global.changeDynObj ) {
|
||||||
// ABu zmiana pojazdu - przejście do innego
|
// ABu zmiana pojazdu - przejście do innego
|
||||||
ChangeDynamic();
|
ChangeDynamic();
|
||||||
@@ -243,15 +258,13 @@ driver_mode::update() {
|
|||||||
InOutKey();
|
InOutKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if( simulation::Train != nullptr ) {
|
if( simulation::Train != nullptr )
|
||||||
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
|
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( simulation::Train->Dynamic() );
|
||||||
simulation::Train->Update( deltatime );
|
else
|
||||||
}
|
|
||||||
else {
|
|
||||||
TSubModel::iInstance = 0;
|
TSubModel::iInstance = 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
simulation::Trains.update(deltatime);
|
||||||
simulation::Events.update();
|
simulation::Events.update();
|
||||||
simulation::Region->update_events();
|
simulation::Region->update_events();
|
||||||
simulation::Lights.update();
|
simulation::Lights.update();
|
||||||
@@ -260,12 +273,16 @@ driver_mode::update() {
|
|||||||
|
|
||||||
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
auto const deltarealtime = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
||||||
|
|
||||||
|
simulation::State.process_commands();
|
||||||
|
|
||||||
// fixed step render time routines
|
// fixed step render time routines
|
||||||
|
|
||||||
fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
fTime50Hz += deltarealtime; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
||||||
bool runonce { false };
|
bool runonce { false };
|
||||||
while( fTime50Hz >= 1.0 / 50.0 ) {
|
while( fTime50Hz >= 1.0 / 50.0 ) {
|
||||||
|
#ifdef _WIN32
|
||||||
Console::Update(); // to i tak trzeba wywoływać
|
Console::Update(); // to i tak trzeba wywoływać
|
||||||
|
#endif
|
||||||
ui::Transcripts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie
|
ui::Transcripts.Update(); // obiekt obsługujący stenogramy dźwięków na ekranie
|
||||||
m_userinterface->update();
|
m_userinterface->update();
|
||||||
// decelerate camera
|
// decelerate camera
|
||||||
@@ -354,8 +371,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], nPlayerTrain );
|
Camera.Init(Global.FreeCameraInit[0], Global.FreeCameraInitAngle[0], nPlayerTrain );
|
||||||
@@ -364,32 +381,17 @@ driver_mode::enter() {
|
|||||||
|
|
||||||
if (nPlayerTrain)
|
if (nPlayerTrain)
|
||||||
{
|
{
|
||||||
WriteLog( "Initializing player train, \"" + Global.asHumanCtrlVehicle + "\"" );
|
WriteLog( "Trying to enter player train, \"" + Global.local_start_vehicle + "\"" );
|
||||||
|
|
||||||
if( simulation::Train == nullptr ) {
|
FreeFlyModeFlag = true; // HACK: entervehicle won't work if the simulation thinks we're outside
|
||||||
simulation::Train = new TTrain();
|
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0, nPlayerTrain->GetPosition());
|
||||||
}
|
change_train = nPlayerTrain->name();
|
||||||
if( simulation::Train->Init( nPlayerTrain ) )
|
|
||||||
{
|
|
||||||
WriteLog("Player train initialization OK");
|
|
||||||
|
|
||||||
Application.set_title( Global.AppName + " (" + simulation::Train->Controlled()->Name + " @ " + Global.SceneryFile + ")" );
|
|
||||||
|
|
||||||
CabView();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Error("Bad init: player train initialization failed");
|
if (Global.local_start_vehicle != "ghostview")
|
||||||
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
|
|
||||||
SafeDelete( simulation::Train );
|
|
||||||
Camera.m_owner = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (Global.asHumanCtrlVehicle != "ghostview")
|
Error("Bad scenario: failed to locate player train, \"" + Global.local_start_vehicle + "\"" );
|
||||||
{
|
|
||||||
Error("Bad scenario: failed to locate player train, \"" + Global.asHumanCtrlVehicle + "\"" );
|
|
||||||
}
|
}
|
||||||
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
|
FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie
|
||||||
Camera.m_owner = nullptr;
|
Camera.m_owner = nullptr;
|
||||||
@@ -459,6 +461,11 @@ driver_mode::on_key( int const Key, int const Scancode, int const Action, int co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_mode::on_char( unsigned int const Char ) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
driver_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
driver_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||||
|
|
||||||
@@ -498,6 +505,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 ) {
|
||||||
|
|
||||||
@@ -759,7 +772,7 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
// z [Shift] uruchomienie eventu
|
// z [Shift] uruchomienie eventu
|
||||||
if( ( Global.iPause == 0 ) // podczas pauzy klawisze nie działają
|
if( ( Global.iPause == 0 ) // podczas pauzy klawisze nie działają
|
||||||
&& ( KeyEvents[ i ] != nullptr ) ) {
|
&& ( KeyEvents[ i ] != nullptr ) ) {
|
||||||
simulation::Events.AddToQuery( KeyEvents[ i ], NULL );
|
m_relay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &KeyEvents[i]->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( Global.ctrlState ) {
|
else if( Global.ctrlState ) {
|
||||||
@@ -794,21 +807,6 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
|
|
||||||
switch (cKey) {
|
switch (cKey) {
|
||||||
|
|
||||||
case GLFW_KEY_F1: {
|
|
||||||
|
|
||||||
if( DebugModeFlag ) {
|
|
||||||
// additional simulation clock jump keys in debug mode
|
|
||||||
if( Global.ctrlState ) {
|
|
||||||
// ctrl-f1
|
|
||||||
simulation::Time.update( 20.0 * 60.0 );
|
|
||||||
}
|
|
||||||
else if( Global.shiftState ) {
|
|
||||||
// shift-f1
|
|
||||||
simulation::Time.update( 5.0 * 60.0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GLFW_KEY_F4: {
|
case GLFW_KEY_F4: {
|
||||||
|
|
||||||
if( Global.shiftState ) { ExternalView(); } // with Shift, cycle through external views
|
if( Global.shiftState ) { ExternalView(); } // with Shift, cycle through external views
|
||||||
@@ -817,6 +815,19 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
}
|
}
|
||||||
case GLFW_KEY_F5: {
|
case GLFW_KEY_F5: {
|
||||||
// przesiadka do innego pojazdu
|
// przesiadka do innego pojazdu
|
||||||
|
if (!FreeFlyModeFlag)
|
||||||
|
// only available in free fly mode
|
||||||
|
break;
|
||||||
|
|
||||||
|
TDynamicObject *dynamic = std::get<TDynamicObject *>( simulation::Region->find_vehicle( Global.pCamera.Pos, 50, false, false ) );
|
||||||
|
if (dynamic) {
|
||||||
|
m_relay.post(user_command::entervehicle, 0.0, 0.0, GLFW_PRESS, 0);
|
||||||
|
|
||||||
|
change_train = dynamic->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
/*
|
||||||
if( false == FreeFlyModeFlag ) {
|
if( false == FreeFlyModeFlag ) {
|
||||||
// only available in free fly mode
|
// only available in free fly mode
|
||||||
break;
|
break;
|
||||||
@@ -872,12 +883,10 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
// we can simply move the 'human' controller to the new vehicle
|
// we can simply move the 'human' controller to the new vehicle
|
||||||
Global.changeDynObj = targetvehicle;
|
Global.changeDynObj = targetvehicle;
|
||||||
// TODO: choose active cab based on camera's location relative to vehicle's location
|
// TODO: choose active cab based on camera's location relative to vehicle's location
|
||||||
/*
|
// Global.changeDynObj->MoverParameters->CabOccupied = (
|
||||||
Global.changeDynObj->MoverParameters->CabOccupied = (
|
// Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
||||||
Train->DynamicObject->MoverParameters->Neighbours[ exitdirection ].vehicle_end ?
|
// -1 :
|
||||||
-1 :
|
// 1 );
|
||||||
1 );
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -905,6 +914,7 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
case GLFW_KEY_F6: {
|
case GLFW_KEY_F6: {
|
||||||
// przyspieszenie symulacji do testowania scenerii... uwaga na FPS!
|
// przyspieszenie symulacji do testowania scenerii... uwaga na FPS!
|
||||||
@@ -954,66 +964,6 @@ driver_mode::OnKeyDown(int cKey) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GLFW_KEY_F12: {
|
|
||||||
// quick debug mode toggle
|
|
||||||
if( Global.ctrlState
|
|
||||||
&& Global.shiftState ) {
|
|
||||||
DebugModeFlag = !DebugModeFlag;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GLFW_KEY_LEFT_BRACKET:
|
|
||||||
case GLFW_KEY_RIGHT_BRACKET:
|
|
||||||
case GLFW_KEY_TAB: {
|
|
||||||
// consist movement in debug mode
|
|
||||||
if( ( true == DebugModeFlag )
|
|
||||||
&& ( false == Global.shiftState )
|
|
||||||
&& ( true == Global.ctrlState )
|
|
||||||
&& ( simulation::Train != nullptr )
|
|
||||||
&& ( simulation::Train->Dynamic()->Controller == Humandriver ) ) {
|
|
||||||
|
|
||||||
if( DebugModeFlag ) {
|
|
||||||
// przesuwanie składu o 100m
|
|
||||||
auto *vehicle { simulation::Train->Dynamic() };
|
|
||||||
TDynamicObject *d = vehicle;
|
|
||||||
if( cKey == GLFW_KEY_LEFT_BRACKET ) {
|
|
||||||
while( d ) {
|
|
||||||
d->Move( 100.0 * d->DirectionGet() );
|
|
||||||
d = d->Next(); // pozostałe też
|
|
||||||
}
|
|
||||||
d = vehicle->Prev();
|
|
||||||
while( d ) {
|
|
||||||
d->Move( 100.0 * d->DirectionGet() );
|
|
||||||
d = d->Prev(); // w drugą stronę też
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( cKey == GLFW_KEY_RIGHT_BRACKET ) {
|
|
||||||
while( d ) {
|
|
||||||
d->Move( -100.0 * d->DirectionGet() );
|
|
||||||
d = d->Next(); // pozostałe też
|
|
||||||
}
|
|
||||||
d = vehicle->Prev();
|
|
||||||
while( d ) {
|
|
||||||
d->Move( -100.0 * d->DirectionGet() );
|
|
||||||
d = d->Prev(); // w drugą stronę też
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( cKey == GLFW_KEY_TAB ) {
|
|
||||||
while( d ) {
|
|
||||||
d->MoverParameters->V += d->DirectionGet()*2.78;
|
|
||||||
d = d->Next(); // pozostałe też
|
|
||||||
}
|
|
||||||
d = vehicle->Prev();
|
|
||||||
while( d ) {
|
|
||||||
d->MoverParameters->V += d->DirectionGet()*2.78;
|
|
||||||
d = d->Prev(); // w drugą stronę też
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
@@ -1267,7 +1217,7 @@ driver_mode::ChangeDynamic() {
|
|||||||
vehicle = train->Dynamic();
|
vehicle = train->Dynamic();
|
||||||
occupied = train->Occupied();
|
occupied = train->Occupied();
|
||||||
driver = vehicle->Mechanik;
|
driver = vehicle->Mechanik;
|
||||||
Global.asHumanCtrlVehicle = vehicle->name();
|
Global.local_start_vehicle = vehicle->name();
|
||||||
if( driver ) // AI może sobie samo pójść
|
if( driver ) // AI może sobie samo pójść
|
||||||
if( false == driver->AIControllFlag ) // tylko jeśli ręcznie prowadzony
|
if( false == driver->AIControllFlag ) // tylko jeśli ręcznie prowadzony
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ public:
|
|||||||
// input handlers
|
// input handlers
|
||||||
void
|
void
|
||||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
||||||
|
void
|
||||||
|
on_char( unsigned int const Char ) override;
|
||||||
void
|
void
|
||||||
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
||||||
void
|
void
|
||||||
@@ -49,6 +51,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
|
||||||
@@ -109,4 +113,6 @@ private:
|
|||||||
double m_primaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for core fixed step routines
|
double m_primaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for core fixed step routines
|
||||||
double m_secondaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for less important fixed step routines
|
double m_secondaryupdateaccumulator { m_secondaryupdaterate }; // keeps track of elapsed simulation time, for less important fixed step routines
|
||||||
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
||||||
|
command_relay m_relay;
|
||||||
|
std::string change_train; // train name awaiting entering
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,22 +47,6 @@ driver_ui::driver_ui() {
|
|||||||
bool
|
bool
|
||||||
driver_ui::on_key_( int const Key, int const Scancode, int const Action, int const Mods ) {
|
driver_ui::on_key_( int const Key, int const Scancode, int const Action, int const Mods ) {
|
||||||
|
|
||||||
if( Key == GLFW_KEY_ESCAPE ) {
|
|
||||||
// toggle pause
|
|
||||||
if( Action != GLFW_PRESS ) { return true; } // recognized, but ignored
|
|
||||||
|
|
||||||
if( Global.iPause & 1 ) {
|
|
||||||
// jeśli pauza startowa
|
|
||||||
// odpauzowanie, gdy po wczytaniu miało nie startować
|
|
||||||
Global.iPause ^= 1;
|
|
||||||
}
|
|
||||||
else if( ( Global.iMultiplayer & 2 ) == 0 ) {
|
|
||||||
// w multiplayerze pauza nie ma sensu
|
|
||||||
Global.iPause ^= 2; // zmiana stanu zapauzowania
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the pause is on ignore block other input
|
// if the pause is on ignore block other input
|
||||||
if( m_paused ) { return true; }
|
if( m_paused ) { return true; }
|
||||||
|
|
||||||
@@ -192,12 +176,13 @@ driver_ui::render_() {
|
|||||||
auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 };
|
auto const popupwidth{ locale::strings[ locale::string::driver_pause_header ].size() * 7 };
|
||||||
if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
|
if( ImGui::Button( locale::strings[ locale::string::driver_pause_resume ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
auto const pausemask { 1 | 2 };
|
command_relay commandrelay;
|
||||||
Global.iPause &= ~pausemask;
|
commandrelay.post(user_command::pausetoggle, 0.0, 0.0, GLFW_PRESS, 0);
|
||||||
}
|
}
|
||||||
if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
|
if( ImGui::Button( locale::strings[ locale::string::driver_pause_quit ].c_str(), ImVec2( popupwidth, 0 ) ) ) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
glfwSetWindowShouldClose( m_window, 1 );
|
command_relay commandrelay;
|
||||||
|
commandrelay.post(user_command::quitsimulation, 0.0, 0.0, GLFW_PRESS, 0);
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,11 @@ editor_mode::on_key( int const Key, int const Scancode, int const Action, int co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
editor_mode::on_char( unsigned int const Char ) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
editor_mode::on_cursor_pos( double const Horizontal, double const Vertical ) {
|
||||||
|
|
||||||
@@ -266,6 +271,12 @@ 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 {
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ public:
|
|||||||
// input handlers
|
// input handlers
|
||||||
void
|
void
|
||||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override;
|
||||||
|
void
|
||||||
|
on_char( unsigned int const Char ) override;
|
||||||
void
|
void
|
||||||
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
on_cursor_pos( double const Horizontal, double const Vertical ) override;
|
||||||
void
|
void
|
||||||
@@ -45,6 +47,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
|
||||||
|
|||||||
@@ -84,10 +84,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/asio/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
@@ -108,10 +108,10 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/asio/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
@@ -128,10 +128,10 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/asio/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
@@ -151,10 +151,10 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glew/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)console;$(SolutionDir)mczapkie;$(SolutionDir)ref/glad/include;$(SolutionDir)ref/glfw/include;$(SolutionDir)ref/glm;$(SolutionDir)ref/openal/include;$(SolutionDir)ref/dr_libs/include;$(SolutionDir)ref/imgui;$(SolutionDir)ref/imgui/examples;$(SolutionDir)ref/python/include;$(SolutionDir)ref/libserialport/include;$(SolutionDir)ref/asio/include;$(SolutionDir)ref/stb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
@@ -234,6 +234,10 @@
|
|||||||
<ClCompile Include="drivermouseinput.cpp" />
|
<ClCompile Include="drivermouseinput.cpp" />
|
||||||
<ClCompile Include="mtable.cpp" />
|
<ClCompile Include="mtable.cpp" />
|
||||||
<ClCompile Include="Names.cpp" />
|
<ClCompile Include="Names.cpp" />
|
||||||
|
<ClCompile Include="network\backend\asio.cpp" />
|
||||||
|
<ClCompile Include="network\manager.cpp" />
|
||||||
|
<ClCompile Include="network\message.cpp" />
|
||||||
|
<ClCompile Include="network\network.cpp" />
|
||||||
<ClCompile Include="opengl33geometrybank.cpp" />
|
<ClCompile Include="opengl33geometrybank.cpp" />
|
||||||
<ClCompile Include="opengl33light.cpp" />
|
<ClCompile Include="opengl33light.cpp" />
|
||||||
<ClCompile Include="opengl33particles.cpp" />
|
<ClCompile Include="opengl33particles.cpp" />
|
||||||
@@ -409,6 +413,10 @@
|
|||||||
<ClInclude Include="drivermouseinput.h" />
|
<ClInclude Include="drivermouseinput.h" />
|
||||||
<ClInclude Include="mtable.h" />
|
<ClInclude Include="mtable.h" />
|
||||||
<ClInclude Include="Names.h" />
|
<ClInclude Include="Names.h" />
|
||||||
|
<ClInclude Include="network\backend\asio.h" />
|
||||||
|
<ClInclude Include="network\manager.h" />
|
||||||
|
<ClInclude Include="network\message.h" />
|
||||||
|
<ClInclude Include="network\network.h" />
|
||||||
<ClInclude Include="opengl33geometrybank.h" />
|
<ClInclude Include="opengl33geometrybank.h" />
|
||||||
<ClInclude Include="opengl33light.h" />
|
<ClInclude Include="opengl33light.h" />
|
||||||
<ClInclude Include="opengl33particles.h" />
|
<ClInclude Include="opengl33particles.h" />
|
||||||
|
|||||||
@@ -70,6 +70,18 @@
|
|||||||
<Filter Include="Source Files\math">
|
<Filter Include="Source Files\math">
|
||||||
<UniqueIdentifier>{dd00198e-a316-4bcc-a4d3-916c8dcfe08f}</UniqueIdentifier>
|
<UniqueIdentifier>{dd00198e-a316-4bcc-a4d3-916c8dcfe08f}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Source Files\application\network">
|
||||||
|
<UniqueIdentifier>{a41f784b-da5a-40de-a4ec-f9b1da1aa607}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\application\network">
|
||||||
|
<UniqueIdentifier>{5a6c58fe-4b3c-4a46-8ef0-71d4c08d7ebe}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\application\network\backend">
|
||||||
|
<UniqueIdentifier>{de8b7596-9589-4320-9008-15e15ebf1d8f}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\application\network\backend">
|
||||||
|
<UniqueIdentifier>{db0ac2d6-9a5d-412e-87b6-8b23c8f8b7a7}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="AirCoupler.cpp">
|
<ClCompile Include="AirCoupler.cpp">
|
||||||
@@ -441,6 +453,18 @@
|
|||||||
<ClCompile Include="opengl33geometrybank.cpp">
|
<ClCompile Include="opengl33geometrybank.cpp">
|
||||||
<Filter>Source Files\gfx</Filter>
|
<Filter>Source Files\gfx</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="network\network.cpp">
|
||||||
|
<Filter>Source Files\application\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="network\manager.cpp">
|
||||||
|
<Filter>Source Files\application\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="network\message.cpp">
|
||||||
|
<Filter>Source Files\application\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="network\backend\asio.cpp">
|
||||||
|
<Filter>Source Files\application\network\backend</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Globals.h">
|
<ClInclude Include="Globals.h">
|
||||||
@@ -812,6 +836,18 @@
|
|||||||
<ClInclude Include="stars.h">
|
<ClInclude Include="stars.h">
|
||||||
<Filter>Header Files\gfx</Filter>
|
<Filter>Header Files\gfx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="network\manager.h">
|
||||||
|
<Filter>Header Files\application\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="network\message.h">
|
||||||
|
<Filter>Header Files\application\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="network\network.h">
|
||||||
|
<Filter>Header Files\application\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="network\backend\asio.h">
|
||||||
|
<Filter>Header Files\application\network\backend</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="maszyna.rc">
|
<ResourceCompile Include="maszyna.rc">
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
|
|||||||
|| ( typeid( *event ) == typeid( lights_event ) )
|
|| ( typeid( *event ) == typeid( lights_event ) )
|
||||||
|| ( event->m_sibling != 0 ) ) {
|
|| ( event->m_sibling != 0 ) ) {
|
||||||
// tylko jawne albo niejawne Multiple
|
// tylko jawne albo niejawne Multiple
|
||||||
simulation::Events.AddToQuery( event, nullptr ); // drugi parametr to dynamic wywołujący - tu brak
|
command_relay relay;
|
||||||
|
relay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &event->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,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::Vehicles.find( Global.local_start_vehicle ) :
|
||||||
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
|
||||||
@@ -180,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::Vehicles.find( Global.local_start_vehicle ) : // 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 };
|
||||||
|
|||||||
244
network/backend/asio.cpp
Normal file
244
network/backend/asio.cpp
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "network/backend/asio.h"
|
||||||
|
|
||||||
|
#include "sn_utils.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
|
||||||
|
network::tcp::connection::connection(asio::io_context &io_ctx, bool client, size_t counter)
|
||||||
|
: network::connection(client, counter),
|
||||||
|
m_socket(io_ctx)
|
||||||
|
{
|
||||||
|
m_header_buffer.resize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
network::tcp::connection::~connection()
|
||||||
|
{
|
||||||
|
m_socket.shutdown(m_socket.shutdown_both);
|
||||||
|
m_socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::disconnect()
|
||||||
|
{
|
||||||
|
network::connection::disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::send_data(std::shared_ptr<std::string> buffer)
|
||||||
|
{
|
||||||
|
asio::async_write(m_socket, asio::buffer(*buffer.get()), std::bind(&connection::send_complete, this, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::connected()
|
||||||
|
{
|
||||||
|
network::connection::connected();
|
||||||
|
read_header();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::read_header()
|
||||||
|
{
|
||||||
|
asio::async_read(m_socket, asio::buffer(m_header_buffer),
|
||||||
|
std::bind(&connection::handle_header, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::handle_header(const asio::error_code &err, size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (err) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream header(m_header_buffer);
|
||||||
|
if (m_header_buffer.size() != bytes_transferred) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sig = sn_utils::ld_uint32(header);
|
||||||
|
if (sig != NETWORK_MAGIC) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t len = sn_utils::ld_uint32(header);
|
||||||
|
m_body_buffer.resize(len);
|
||||||
|
if (len > MAX_MSG_SIZE) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::async_read(m_socket, asio::buffer(m_body_buffer),
|
||||||
|
std::bind(&connection::handle_data, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::handle_data(const asio::error_code &err, size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (err) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_body_buffer.size() != bytes_transferred) {
|
||||||
|
disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream stream(m_body_buffer);
|
||||||
|
std::shared_ptr<message> msg = deserialize_message(stream);
|
||||||
|
if (message_handler)
|
||||||
|
message_handler(*msg);
|
||||||
|
|
||||||
|
read_header();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::write_message(const message &msg, std::ostream &stream)
|
||||||
|
{
|
||||||
|
size_t beg = (size_t)stream.tellp();
|
||||||
|
|
||||||
|
sn_utils::ls_uint32(stream, NETWORK_MAGIC);
|
||||||
|
sn_utils::ls_uint32(stream, 0);
|
||||||
|
|
||||||
|
serialize_message(msg, stream);
|
||||||
|
|
||||||
|
size_t size = (size_t)stream.tellp() - beg - 8;
|
||||||
|
if (size > MAX_MSG_SIZE) {
|
||||||
|
ErrorLog("net: message too big", logtype::net);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stream.seekp(beg + 4, std::ios_base::beg);
|
||||||
|
sn_utils::ls_uint32(stream, size);
|
||||||
|
|
||||||
|
stream.seekp(0, std::ios_base::end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::send_messages(const std::vector<std::shared_ptr<message> > &messages)
|
||||||
|
{
|
||||||
|
if (messages.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::ostringstream stream;
|
||||||
|
for (auto const &msg : messages)
|
||||||
|
write_message(*msg.get(), stream);
|
||||||
|
|
||||||
|
stream.flush();
|
||||||
|
send_data(std::make_shared<std::string>(stream.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::connection::send_message(const message &msg)
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
write_message(msg, stream);
|
||||||
|
|
||||||
|
stream.flush();
|
||||||
|
send_data(std::make_shared<std::string>(stream.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------
|
||||||
|
|
||||||
|
network::tcp::server::server(std::shared_ptr<std::istream> buf, asio::io_context &io_ctx, const std::string &host, uint32_t port)
|
||||||
|
: network::server(buf), m_acceptor(io_ctx)
|
||||||
|
{
|
||||||
|
auto endpoint = asio::ip::tcp::endpoint(asio::ip::address::from_string(host), port);
|
||||||
|
m_acceptor.open(endpoint.protocol());
|
||||||
|
m_acceptor.set_option(asio::socket_base::reuse_address(true));
|
||||||
|
m_acceptor.set_option(asio::ip::tcp::no_delay(true));
|
||||||
|
m_acceptor.bind(endpoint);
|
||||||
|
m_acceptor.listen(10);
|
||||||
|
|
||||||
|
accept_conn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::server::accept_conn()
|
||||||
|
{
|
||||||
|
std::shared_ptr<connection> conn = std::make_shared<connection>(m_acceptor.get_executor().context());
|
||||||
|
conn->set_handler(std::bind(&server::handle_message, this, conn, std::placeholders::_1));
|
||||||
|
|
||||||
|
m_acceptor.async_accept(conn->m_socket, std::bind(&server::handle_accept, this, conn, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::server::handle_accept(std::shared_ptr<connection> conn, const asio::error_code &err)
|
||||||
|
{
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
clients.emplace_back(conn);
|
||||||
|
conn->connected();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conn->state = connection::DEAD;
|
||||||
|
WriteLog(std::string("net: failed to accept client: " + err.message()), logtype::net);
|
||||||
|
}
|
||||||
|
|
||||||
|
accept_conn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------
|
||||||
|
|
||||||
|
network::tcp::client::client(asio::io_context &io_ctxx, const std::string &hostarg, uint32_t portarg)
|
||||||
|
: host(hostarg), port(portarg), io_ctx(io_ctxx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::client::connect()
|
||||||
|
{
|
||||||
|
if (this->conn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
asio::ip::tcp::endpoint endpoint(
|
||||||
|
asio::ip::address::from_string(host), port);
|
||||||
|
conn->m_socket.open(endpoint.protocol());
|
||||||
|
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));
|
||||||
|
|
||||||
|
this->conn = conn;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::client::handle_accept(const asio::error_code &err)
|
||||||
|
{
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
conn->connected();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog(std::string("net: failed to connect: " + err.message()), logtype::net);
|
||||||
|
conn->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network::tcp::asio_manager::asio_manager() {
|
||||||
|
backend_list().emplace("tcp", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<network::server> network::tcp::asio_manager::create_server(std::shared_ptr<std::fstream> backbuffer, const std::string &conf) {
|
||||||
|
std::istringstream stream(conf);
|
||||||
|
|
||||||
|
std::string host;
|
||||||
|
std::getline(stream, host, ':');
|
||||||
|
|
||||||
|
int port;
|
||||||
|
stream >> port;
|
||||||
|
|
||||||
|
return std::make_shared<tcp::server>(backbuffer, io_context, host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<network::client> network::tcp::asio_manager::create_client(const std::string &conf) {
|
||||||
|
std::istringstream stream(conf);
|
||||||
|
|
||||||
|
std::string host;
|
||||||
|
std::getline(stream, host, ':');
|
||||||
|
|
||||||
|
int port;
|
||||||
|
stream >> port;
|
||||||
|
|
||||||
|
return std::make_shared<tcp::client>(io_context, host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::tcp::asio_manager::update() {
|
||||||
|
io_context.restart();
|
||||||
|
io_context.poll();
|
||||||
|
}
|
||||||
82
network/backend/asio.h
Normal file
82
network/backend/asio.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#define ASIO_STANDALONE
|
||||||
|
|
||||||
|
#ifdef DBG_NEW
|
||||||
|
#undef new
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <asio.hpp>
|
||||||
|
|
||||||
|
#include "network/network.h"
|
||||||
|
|
||||||
|
namespace network::tcp
|
||||||
|
{
|
||||||
|
const uint32_t NETWORK_MAGIC = 0x37305545;
|
||||||
|
const uint32_t MAX_MSG_SIZE = 100000;
|
||||||
|
|
||||||
|
class connection : public network::connection
|
||||||
|
{
|
||||||
|
friend class server;
|
||||||
|
friend class client;
|
||||||
|
|
||||||
|
public:
|
||||||
|
connection(asio::io_context &io_ctx, bool client = false, size_t counter = 0);
|
||||||
|
~connection();
|
||||||
|
|
||||||
|
virtual void connected() override;
|
||||||
|
virtual void disconnect() override;
|
||||||
|
virtual void send_messages(const std::vector<std::shared_ptr<message> > &messages) override;
|
||||||
|
virtual void send_message(const message &msg) override;
|
||||||
|
|
||||||
|
asio::ip::tcp::socket m_socket;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_header_buffer;
|
||||||
|
std::string m_body_buffer;
|
||||||
|
|
||||||
|
void write_message(const message &msg, std::ostream &stream);
|
||||||
|
void send_data(std::shared_ptr<std::string> buffer);
|
||||||
|
void read_header();
|
||||||
|
void handle_header(const asio::error_code &err, size_t bytes_transferred);
|
||||||
|
void handle_data(const asio::error_code &err, size_t bytes_transferred);
|
||||||
|
};
|
||||||
|
|
||||||
|
class server : public network::server
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void accept_conn();
|
||||||
|
void handle_accept(std::shared_ptr<connection> conn, const asio::error_code &err);
|
||||||
|
|
||||||
|
asio::ip::tcp::acceptor m_acceptor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
server(std::shared_ptr<std::istream> buf, asio::io_context &io_ctx, const std::string &host, uint32_t port);
|
||||||
|
};
|
||||||
|
|
||||||
|
class client : public network::client
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void handle_accept(const asio::error_code &err);
|
||||||
|
asio::io_context &io_ctx;
|
||||||
|
std::string host;
|
||||||
|
uint32_t port;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void connect() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
client(asio::io_context &io_ctx, const std::string &host, uint32_t port);
|
||||||
|
};
|
||||||
|
|
||||||
|
class asio_manager : public network::backend_manager {
|
||||||
|
asio::io_context io_context;
|
||||||
|
|
||||||
|
public:
|
||||||
|
asio_manager();
|
||||||
|
|
||||||
|
virtual std::shared_ptr<network::server> create_server(std::shared_ptr<std::fstream>, const std::string &conf) override;
|
||||||
|
virtual std::shared_ptr<network::client> create_client(const std::string &conf) override;
|
||||||
|
virtual void update() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
asio_manager manager;
|
||||||
|
}
|
||||||
89
network/manager.cpp
Normal file
89
network/manager.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "network/manager.h"
|
||||||
|
|
||||||
|
#include "simulation.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
|
||||||
|
network::server_manager::server_manager()
|
||||||
|
{
|
||||||
|
backbuffer = std::make_shared<std::fstream>("backbuffer.bin", std::ios::out | std::ios::in | std::ios::trunc | std::ios::binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_queue::commands_map network::server_manager::pop_commands()
|
||||||
|
{
|
||||||
|
command_queue::commands_map map;
|
||||||
|
|
||||||
|
for (auto srv : servers)
|
||||||
|
add_to_dequemap(map, srv->pop_commands());
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server_manager::push_delta(double render_dt, double dt, double sync, const command_queue::commands_map &commands)
|
||||||
|
{
|
||||||
|
if (dt == 0.0 && commands.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
frame_info msg;
|
||||||
|
msg.render_dt = render_dt;
|
||||||
|
msg.dt = dt;
|
||||||
|
msg.sync = sync;
|
||||||
|
msg.commands = commands;
|
||||||
|
|
||||||
|
for (auto srv : servers)
|
||||||
|
srv->push_delta(msg);
|
||||||
|
|
||||||
|
serialize_message(msg, *backbuffer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server_manager::create_server(const std::string &backend, const std::string &conf)
|
||||||
|
{
|
||||||
|
auto it = backend_list().find(backend);
|
||||||
|
if (it == backend_list().end()) {
|
||||||
|
ErrorLog("net: unknown backend: " + backend);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
servers.emplace_back(it->second->create_server(backbuffer, conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
network::manager::manager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::manager::update()
|
||||||
|
{
|
||||||
|
for (auto &backend : backend_list())
|
||||||
|
backend.second->update();
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
client->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::manager::create_server(const std::string &backend, const std::string &conf)
|
||||||
|
{
|
||||||
|
servers.emplace();
|
||||||
|
servers->create_server(backend, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::manager::connect(const std::string &backend, const std::string &conf)
|
||||||
|
{
|
||||||
|
auto it = backend_list().find(backend);
|
||||||
|
if (it == backend_list().end()) {
|
||||||
|
ErrorLog("net: unknown backend: " + backend);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client = it->second->create_client(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::unordered_map<std::string, std::shared_ptr<network::backend_manager>> network::backend_list;
|
||||||
34
network/manager.h
Normal file
34
network/manager.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "network/network.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
namespace network
|
||||||
|
{
|
||||||
|
class server_manager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<server>> servers;
|
||||||
|
std::shared_ptr<std::fstream> backbuffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
server_manager();
|
||||||
|
|
||||||
|
void push_delta(double render_dt, double dt, double sync, const command_queue::commands_map &commands);
|
||||||
|
command_queue::commands_map pop_commands();
|
||||||
|
void create_server(const std::string &backend, const std::string &conf);
|
||||||
|
};
|
||||||
|
|
||||||
|
class manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
manager();
|
||||||
|
|
||||||
|
std::optional<server_manager> servers;
|
||||||
|
std::shared_ptr<network::client> client;
|
||||||
|
|
||||||
|
void create_server(const std::string &backend, const std::string &conf);
|
||||||
|
void connect(const std::string &backend, const std::string &conf);
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
}
|
||||||
124
network/message.cpp
Normal file
124
network/message.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "network/message.h"
|
||||||
|
#include "sn_utils.h"
|
||||||
|
|
||||||
|
void network::client_hello::serialize(std::ostream &stream) const
|
||||||
|
{
|
||||||
|
sn_utils::ls_int32(stream, version);
|
||||||
|
sn_utils::ls_uint32(stream, start_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::client_hello::deserialize(std::istream &stream)
|
||||||
|
{
|
||||||
|
version = sn_utils::ld_int32(stream);
|
||||||
|
start_packet = sn_utils::ld_uint32(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server_hello::serialize(std::ostream &stream) const
|
||||||
|
{
|
||||||
|
sn_utils::ls_uint32(stream, seed);
|
||||||
|
sn_utils::ls_int64(stream, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server_hello::deserialize(std::istream &stream)
|
||||||
|
{
|
||||||
|
seed = sn_utils::ld_uint32(stream);
|
||||||
|
timestamp = sn_utils::ld_int64(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ::network::request_command::serialize(std::ostream &stream) const
|
||||||
|
{
|
||||||
|
sn_utils::ls_uint32(stream, commands.size());
|
||||||
|
for (auto const &kv : commands)
|
||||||
|
{
|
||||||
|
sn_utils::ls_uint32(stream, kv.first);
|
||||||
|
sn_utils::ls_uint32(stream, kv.second.size());
|
||||||
|
for (command_data const &data : kv.second)
|
||||||
|
{
|
||||||
|
sn_utils::ls_uint32(stream, (uint32_t)data.command);
|
||||||
|
sn_utils::ls_int32(stream, data.action);
|
||||||
|
sn_utils::ls_float64(stream, data.param1);
|
||||||
|
sn_utils::ls_float64(stream, data.param2);
|
||||||
|
sn_utils::ls_float64(stream, data.time_delta);
|
||||||
|
|
||||||
|
sn_utils::s_bool(stream, data.freefly);
|
||||||
|
sn_utils::s_vec3(stream, data.location);
|
||||||
|
|
||||||
|
sn_utils::s_str(stream, data.payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::request_command::deserialize(std::istream &stream)
|
||||||
|
{
|
||||||
|
uint32_t commands_size = sn_utils::ld_uint32(stream);
|
||||||
|
for (uint32_t i = 0; i < commands_size; i++)
|
||||||
|
{
|
||||||
|
uint32_t recipient = sn_utils::ld_uint32(stream);
|
||||||
|
uint32_t sequence_size = sn_utils::ld_uint32(stream);
|
||||||
|
|
||||||
|
command_queue::commanddata_sequence sequence;
|
||||||
|
for (uint32_t i = 0; i < sequence_size; i++)
|
||||||
|
{
|
||||||
|
command_data data;
|
||||||
|
data.command = (user_command)sn_utils::ld_uint32(stream);
|
||||||
|
data.action = sn_utils::ld_int32(stream);
|
||||||
|
data.param1 = sn_utils::ld_float64(stream);
|
||||||
|
data.param2 = sn_utils::ld_float64(stream);
|
||||||
|
data.time_delta = sn_utils::ld_float64(stream);
|
||||||
|
|
||||||
|
data.freefly = sn_utils::d_bool(stream);
|
||||||
|
data.location = sn_utils::d_vec3(stream);
|
||||||
|
|
||||||
|
data.payload = sn_utils::d_str(stream);
|
||||||
|
|
||||||
|
sequence.emplace_back(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.emplace(recipient, sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::frame_info::serialize(std::ostream &stream) const
|
||||||
|
{
|
||||||
|
sn_utils::ls_float64(stream, render_dt);
|
||||||
|
sn_utils::ls_float64(stream, dt);
|
||||||
|
sn_utils::ls_float64(stream, sync);
|
||||||
|
|
||||||
|
request_command::serialize(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::frame_info::deserialize(std::istream &stream)
|
||||||
|
{
|
||||||
|
render_dt = sn_utils::ld_float64(stream);
|
||||||
|
dt = sn_utils::ld_float64(stream);
|
||||||
|
sync = sn_utils::ld_float64(stream);
|
||||||
|
|
||||||
|
request_command::deserialize(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<network::message> network::deserialize_message(std::istream &stream)
|
||||||
|
{
|
||||||
|
message::type_e type = (message::type_e)sn_utils::ld_uint16(stream);
|
||||||
|
|
||||||
|
std::shared_ptr<message> msg;
|
||||||
|
|
||||||
|
if (type == message::CLIENT_HELLO)
|
||||||
|
msg = std::make_shared<client_hello>();
|
||||||
|
else if (type == message::SERVER_HELLO)
|
||||||
|
msg = std::make_shared<server_hello>();
|
||||||
|
else if (type == message::FRAME_INFO)
|
||||||
|
msg = std::make_shared<frame_info>();
|
||||||
|
else if (type == message::REQUEST_COMMAND)
|
||||||
|
msg = std::make_shared<request_command>();
|
||||||
|
|
||||||
|
msg->deserialize(stream);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::serialize_message(const message &msg, std::ostream &stream)
|
||||||
|
{
|
||||||
|
sn_utils::ls_uint16(stream, (uint16_t)msg.type);
|
||||||
|
msg.serialize(stream);
|
||||||
|
}
|
||||||
73
network/message.h
Normal file
73
network/message.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "network/message.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
namespace network
|
||||||
|
{
|
||||||
|
struct message
|
||||||
|
{
|
||||||
|
enum type_e
|
||||||
|
{
|
||||||
|
CLIENT_HELLO = 0,
|
||||||
|
SERVER_HELLO,
|
||||||
|
FRAME_INFO,
|
||||||
|
REQUEST_COMMAND,
|
||||||
|
TYPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
type_e type;
|
||||||
|
|
||||||
|
message(type_e t) : type(t) {}
|
||||||
|
virtual void serialize(std::ostream &stream) const {}
|
||||||
|
virtual void deserialize(std::istream &stream) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct client_hello : public message
|
||||||
|
{
|
||||||
|
client_hello() : message(CLIENT_HELLO) {}
|
||||||
|
|
||||||
|
virtual void serialize(std::ostream &stream) const override;
|
||||||
|
virtual void deserialize(std::istream &stream) override;
|
||||||
|
|
||||||
|
int32_t version;
|
||||||
|
uint32_t start_packet;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct server_hello : public message
|
||||||
|
{
|
||||||
|
server_hello() : message(SERVER_HELLO) {}
|
||||||
|
|
||||||
|
uint32_t seed;
|
||||||
|
int64_t timestamp;
|
||||||
|
|
||||||
|
virtual void serialize(std::ostream &stream) const override;
|
||||||
|
virtual void deserialize(std::istream &stream) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct request_command : public message
|
||||||
|
{
|
||||||
|
request_command(type_e type) : message(type) {}
|
||||||
|
request_command() : message(REQUEST_COMMAND) {}
|
||||||
|
|
||||||
|
command_queue::commands_map commands;
|
||||||
|
|
||||||
|
virtual void serialize(std::ostream &stream) const override;
|
||||||
|
virtual void deserialize(std::istream &stream) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frame_info : public request_command
|
||||||
|
{
|
||||||
|
frame_info() : request_command(FRAME_INFO) {}
|
||||||
|
|
||||||
|
double render_dt;
|
||||||
|
double dt;
|
||||||
|
double sync;
|
||||||
|
|
||||||
|
virtual void serialize(std::ostream &stream) const override;
|
||||||
|
virtual void deserialize(std::istream &stream) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<message> deserialize_message(std::istream &stream);
|
||||||
|
void serialize_message(const message &msg, std::ostream &stream);
|
||||||
|
} // namespace network
|
||||||
269
network/network.cpp
Normal file
269
network/network.cpp
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "network/network.h"
|
||||||
|
#include "network/message.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
#include "sn_utils.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "application.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
namespace network {
|
||||||
|
|
||||||
|
backend_list_t& backend_list() {
|
||||||
|
// HACK: static initialization order fiasco fix
|
||||||
|
// NOTE: potential static deinitialization order fiasco
|
||||||
|
static backend_list_t backend_list;
|
||||||
|
return backend_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// connection
|
||||||
|
|
||||||
|
void network::connection::disconnect() {
|
||||||
|
WriteLog("net: peer dropped", logtype::net);
|
||||||
|
state = DEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::connection::set_handler(std::function<void (const message &)> handler) {
|
||||||
|
message_handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
network::connection::connection(bool client, size_t counter) {
|
||||||
|
packet_counter = counter;
|
||||||
|
is_client = client;
|
||||||
|
state = AWAITING_HELLO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::connection::connected()
|
||||||
|
{
|
||||||
|
WriteLog("net: socket connected", logtype::net);
|
||||||
|
|
||||||
|
if (is_client) {
|
||||||
|
client_hello msg;
|
||||||
|
msg.version = 1;
|
||||||
|
msg.start_packet = packet_counter;
|
||||||
|
send_message(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::connection::catch_up()
|
||||||
|
{
|
||||||
|
backbuffer->seekg(backbuffer_pos);
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<message>> messages;
|
||||||
|
|
||||||
|
for (int i = 0; i < CATCHUP_PACKETS; i++) {
|
||||||
|
if (backbuffer->peek() == EOF) {
|
||||||
|
send_messages(messages);
|
||||||
|
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(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!is_client && state == CATCHING_UP) {
|
||||||
|
catch_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------
|
||||||
|
|
||||||
|
// server
|
||||||
|
network::server::server(std::shared_ptr<std::istream> buf) : backbuffer(buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server::push_delta(const frame_info &msg)
|
||||||
|
{
|
||||||
|
for (auto it = clients.begin(); it != clients.end(); ) {
|
||||||
|
if ((*it)->state == connection::DEAD) {
|
||||||
|
it = clients.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*it)->state == connection::ACTIVE)
|
||||||
|
(*it)->send_message(msg);
|
||||||
|
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_queue::commands_map network::server::pop_commands()
|
||||||
|
{
|
||||||
|
command_queue::commands_map map(client_commands_queue);
|
||||||
|
client_commands_queue.clear();
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::server::handle_message(std::shared_ptr<connection> conn, const message &msg)
|
||||||
|
{
|
||||||
|
if (msg.type == message::TYPE_MAX)
|
||||||
|
{
|
||||||
|
conn->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.type == message::CLIENT_HELLO) {
|
||||||
|
auto cmd = dynamic_cast<const client_hello&>(msg);
|
||||||
|
|
||||||
|
if (cmd.version != 1 // wrong version
|
||||||
|
|| !Global.ready_to_load) { // not ready yet
|
||||||
|
conn->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_hello reply;
|
||||||
|
reply.seed = Global.random_seed;
|
||||||
|
reply.timestamp = Global.starting_timestamp;
|
||||||
|
conn->state = connection::CATCHING_UP;
|
||||||
|
conn->backbuffer = backbuffer;
|
||||||
|
conn->backbuffer_pos = 0;
|
||||||
|
conn->packet_counter = cmd.start_packet;
|
||||||
|
|
||||||
|
conn->send_message(reply);
|
||||||
|
|
||||||
|
WriteLog("net: client accepted", logtype::net);
|
||||||
|
}
|
||||||
|
else if (msg.type == message::REQUEST_COMMAND) {
|
||||||
|
auto cmd = dynamic_cast<const request_command&>(msg);
|
||||||
|
|
||||||
|
for (auto const &kv : cmd.commands)
|
||||||
|
client_commands_queue.emplace(kv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------
|
||||||
|
|
||||||
|
void network::client::update()
|
||||||
|
{
|
||||||
|
if (conn && conn->state == connection::DEAD) {
|
||||||
|
conn.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conn) {
|
||||||
|
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(int counter)
|
||||||
|
{
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
if (counter == 1) {
|
||||||
|
frame_time = now - last_frame;
|
||||||
|
last_frame = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta_queue.empty()) {
|
||||||
|
// buffer underflow
|
||||||
|
return std::tuple<double, double,
|
||||||
|
command_queue::commands_map>(0.0, 0.0, command_queue::commands_map());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float size = delta_queue.size() - consume_counter;
|
||||||
|
auto entry = delta_queue.front();
|
||||||
|
float mult = entry.render_dt / std::chrono::duration_cast<std::chrono::duration<float>>(frame_time).count();
|
||||||
|
|
||||||
|
if (counter == 1 && size < MAX_BUFFER_SIZE * 2.0f) {
|
||||||
|
last_target = last_target * TARGET_MIX +
|
||||||
|
(std::min(TARGET_MIN + jitteriness * JITTERINESS_MULTIPIER, MAX_BUFFER_SIZE)) * (1.0f - TARGET_MIX);
|
||||||
|
float diff = size - last_target;
|
||||||
|
jitteriness = std::max(jitteriness * JITTERINESS_MIX, std::abs(diff));
|
||||||
|
|
||||||
|
float speed = 1.0f + diff * CONSUME_MULTIPIER;
|
||||||
|
|
||||||
|
consume_counter += speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float last_rcv_diff = std::chrono::duration_cast<std::chrono::duration<float>>(now - last_rcv).count();
|
||||||
|
|
||||||
|
if (size > MAX_BUFFER_SIZE || consume_counter > mult || last_rcv_diff > 1.0f) {
|
||||||
|
if (consume_counter > mult) {
|
||||||
|
consume_counter = std::clamp(consume_counter - mult, -MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
delta_queue.pop();
|
||||||
|
|
||||||
|
return std::make_tuple(entry.dt, entry.sync, entry.commands);
|
||||||
|
} else {
|
||||||
|
// nothing to push
|
||||||
|
return std::tuple<double, double,
|
||||||
|
command_queue::commands_map>(0.0, 0.0, command_queue::commands_map());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::client::send_commands(command_queue::commands_map commands)
|
||||||
|
{
|
||||||
|
if (!conn || conn->state == connection::DEAD || commands.empty())
|
||||||
|
return;
|
||||||
|
// eh, maybe queue lost messages
|
||||||
|
|
||||||
|
request_command msg;
|
||||||
|
msg.commands = commands;
|
||||||
|
|
||||||
|
conn->send_message(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network::client::handle_message(std::shared_ptr<connection> conn, const message &msg)
|
||||||
|
{
|
||||||
|
if (msg.type >= message::TYPE_MAX)
|
||||||
|
{
|
||||||
|
conn->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.type == message::SERVER_HELLO) {
|
||||||
|
auto cmd = dynamic_cast<const server_hello&>(msg);
|
||||||
|
conn->state = connection::ACTIVE;
|
||||||
|
|
||||||
|
if (!Global.ready_to_load) {
|
||||||
|
Global.random_seed = cmd.seed;
|
||||||
|
Global.random_engine.seed(Global.random_seed);
|
||||||
|
Global.starting_timestamp = cmd.timestamp;
|
||||||
|
Global.ready_to_load = true;
|
||||||
|
} else if (Global.random_seed != cmd.seed) {
|
||||||
|
ErrorLog("net: seed mismatch", logtype::net);
|
||||||
|
conn->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteLog("net: accept received", logtype::net);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->state != connection::ACTIVE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (msg.type == message::FRAME_INFO) {
|
||||||
|
resume_frame_counter++;
|
||||||
|
|
||||||
|
auto delta = dynamic_cast<const frame_info&>(msg);
|
||||||
|
delta_queue.push(delta);
|
||||||
|
last_rcv = std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------
|
||||||
122
network/network.h
Normal file
122
network/network.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
|
#include <chrono>
|
||||||
|
#include "network/message.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
namespace network
|
||||||
|
{
|
||||||
|
//m7todo: separate client/server connection class?
|
||||||
|
class connection
|
||||||
|
{
|
||||||
|
friend class server;
|
||||||
|
friend class client;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int CATCHUP_PACKETS = 300;
|
||||||
|
|
||||||
|
bool is_client;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<std::istream> backbuffer;
|
||||||
|
size_t backbuffer_pos;
|
||||||
|
size_t packet_counter;
|
||||||
|
|
||||||
|
void send_complete(std::shared_ptr<std::string> buf);
|
||||||
|
void catch_up();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::function<void(const message &msg)> message_handler;
|
||||||
|
|
||||||
|
virtual void connected() = 0;
|
||||||
|
virtual void send_message(const message &msg) = 0;
|
||||||
|
virtual void send_messages(const std::vector<std::shared_ptr<message>> &messages) = 0;
|
||||||
|
|
||||||
|
connection(bool client = false, size_t counter = 0);
|
||||||
|
void set_handler(std::function<void(const message &msg)> handler);
|
||||||
|
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
|
||||||
|
enum peer_state {
|
||||||
|
AWAITING_HELLO,
|
||||||
|
CATCHING_UP,
|
||||||
|
ACTIVE,
|
||||||
|
DEAD
|
||||||
|
};
|
||||||
|
peer_state state;
|
||||||
|
};
|
||||||
|
|
||||||
|
class server
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::shared_ptr<std::istream> backbuffer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handle_message(std::shared_ptr<connection> conn, const message &msg);
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<connection>> clients;
|
||||||
|
|
||||||
|
command_queue::commands_map client_commands_queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
server(std::shared_ptr<std::istream> buf);
|
||||||
|
void push_delta(const frame_info &msg);
|
||||||
|
command_queue::commands_map pop_commands();
|
||||||
|
};
|
||||||
|
|
||||||
|
class client
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual void connect() = 0;
|
||||||
|
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;
|
||||||
|
const float MAX_BUFFER_SIZE = 60.0f;
|
||||||
|
const float JITTERINESS_MIX = 0.998f;
|
||||||
|
const float TARGET_MIN = 2.0f;
|
||||||
|
const float TARGET_MIX = 0.98f;
|
||||||
|
const float JITTERINESS_MULTIPIER = 2.0f;
|
||||||
|
const float CONSUME_MULTIPIER = 0.05f;
|
||||||
|
|
||||||
|
std::queue<frame_info> delta_queue;
|
||||||
|
|
||||||
|
float last_target = 20.0f;
|
||||||
|
float jitteriness = 1.0f;
|
||||||
|
float consume_counter = 0.0f;
|
||||||
|
|
||||||
|
std::chrono::high_resolution_clock::time_point last_rcv;
|
||||||
|
std::chrono::high_resolution_clock::time_point last_frame;
|
||||||
|
std::chrono::high_resolution_clock::duration frame_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void update();
|
||||||
|
std::tuple<double, double, command_queue::commands_map> get_next_delta(int counter);
|
||||||
|
void send_commands(command_queue::commands_map commands);
|
||||||
|
int get_frame_counter() {
|
||||||
|
return resume_frame_counter;
|
||||||
|
}
|
||||||
|
int get_awaiting_frames() {
|
||||||
|
return delta_queue.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class backend_manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<server> create_server(std::shared_ptr<std::fstream>, const std::string &conf) = 0;
|
||||||
|
virtual std::shared_ptr<client> create_client(const std::string &conf) = 0;
|
||||||
|
virtual void update() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// HACK: static initialization order fiasco fix
|
||||||
|
// extern std::unordered_map<std::string, backend_manager*> backend_list;
|
||||||
|
using backend_list_t = std::unordered_map<std::string, backend_manager*>;
|
||||||
|
backend_list_t& backend_list();
|
||||||
|
}
|
||||||
@@ -37,21 +37,34 @@ scenarioloader_mode::init() {
|
|||||||
bool
|
bool
|
||||||
scenarioloader_mode::update() {
|
scenarioloader_mode::update() {
|
||||||
|
|
||||||
|
if (!Global.ready_to_load)
|
||||||
|
// waiting for network connection
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
WriteLog("using simulation seed: " + std::to_string(Global.random_seed), logtype::generic);
|
||||||
|
|
||||||
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." );
|
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
|
|
||||||
Application.pop_mode();
|
|
||||||
Application.push_mode( eu07_application::mode::driver );
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
try {
|
||||||
|
if (simulation::State.deserialize_continue(state))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (invalid_scenery_exception &e) {
|
||||||
ErrorLog( "Bad init: scenario loading failed" );
|
ErrorLog( "Bad init: scenario loading failed" );
|
||||||
Application.pop_mode();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +88,6 @@ scenarioloader_mode::enter() {
|
|||||||
void
|
void
|
||||||
scenarioloader_mode::exit() {
|
scenarioloader_mode::exit() {
|
||||||
|
|
||||||
simulation::Time.init();
|
simulation::Time.init( Global.starting_timestamp );
|
||||||
simulation::Environment.init();
|
simulation::Environment.init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -32,6 +35,8 @@ public:
|
|||||||
// input handlers
|
// input handlers
|
||||||
void
|
void
|
||||||
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; }
|
on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; }
|
||||||
|
void
|
||||||
|
on_char( unsigned int const Char ) override { ; }
|
||||||
void
|
void
|
||||||
on_cursor_pos( double const Horizontal, double const Vertical ) override { ; }
|
on_cursor_pos( double const Horizontal, double const Vertical ) override { ; }
|
||||||
void
|
void
|
||||||
@@ -40,4 +45,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 { return false; }
|
||||||
};
|
};
|
||||||
|
|||||||
33
scene.cpp
33
scene.cpp
@@ -35,7 +35,7 @@ basic_cell::on_click( TAnimModel const *Instance ) {
|
|||||||
if( ( launcher->name() == Instance->name() )
|
if( ( launcher->name() == Instance->name() )
|
||||||
&& ( glm::length2( launcher->location() - Instance->location() ) < launcher->dRadius )
|
&& ( glm::length2( launcher->location() - Instance->location() ) < launcher->dRadius )
|
||||||
&& ( true == launcher->check_conditions() ) ) {
|
&& ( true == launcher->check_conditions() ) ) {
|
||||||
launch_event( launcher );
|
launch_event( launcher, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,11 +123,13 @@ basic_cell::update_events() {
|
|||||||
|
|
||||||
// event launchers
|
// event launchers
|
||||||
for( auto *launcher : m_eventlaunchers ) {
|
for( auto *launcher : m_eventlaunchers ) {
|
||||||
if( ( true == ( launcher->check_activation() && launcher->check_conditions() ) )
|
if( launcher->check_conditions()
|
||||||
&& ( ( launcher->dRadius < 0.0 )
|
&& ( launcher->dRadius < 0.0
|
||||||
|| ( SquareMagnitude( launcher->location() - Global.pCamera.Pos ) < launcher->dRadius ) ) ) {
|
|| SquareMagnitude( launcher->location() - Global.pCamera.Pos ) < launcher->dRadius ) ) {
|
||||||
|
if( launcher->check_activation() )
|
||||||
launch_event( launcher );
|
launch_event( launcher, true );
|
||||||
|
if( launcher->check_activation_key() )
|
||||||
|
launch_event( launcher, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -608,16 +610,19 @@ basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
|
|
||||||
// executes event assigned to specified launcher
|
// executes event assigned to specified launcher
|
||||||
void
|
void
|
||||||
basic_cell::launch_event( TEventLauncher *Launcher ) {
|
basic_cell::launch_event( TEventLauncher *Launcher, bool local_only ) {
|
||||||
|
WriteLog( "Eventlauncher: " + Launcher->name() );
|
||||||
WriteLog( "Eventlauncher " + Launcher->name() );
|
if (!local_only) {
|
||||||
if( ( true == Global.shiftState )
|
if( Launcher->Event1 ) {
|
||||||
&& ( Launcher->Event2 != nullptr ) ) {
|
|
||||||
simulation::Events.AddToQuery( Launcher->Event2, nullptr );
|
|
||||||
}
|
|
||||||
else if( Launcher->Event1 ) {
|
|
||||||
simulation::Events.AddToQuery( Launcher->Event1, nullptr );
|
simulation::Events.AddToQuery( Launcher->Event1, nullptr );
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
command_relay commandrelay;
|
||||||
|
if (Global.shiftState && Launcher->Event2 != nullptr)
|
||||||
|
commandrelay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &Launcher->Event2->name());
|
||||||
|
else if (Launcher->Event1)
|
||||||
|
commandrelay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &Launcher->Event1->name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjusts cell bounding area to enclose specified node
|
// adjusts cell bounding area to enclose specified node
|
||||||
|
|||||||
2
scene.h
2
scene.h
@@ -173,7 +173,7 @@ private:
|
|||||||
using memorycell_sequence = std::vector<TMemCell *>;
|
using memorycell_sequence = std::vector<TMemCell *>;
|
||||||
// methods
|
// methods
|
||||||
void
|
void
|
||||||
launch_event( TEventLauncher *Launcher );
|
launch_event(TEventLauncher *Launcher, bool local_only);
|
||||||
void
|
void
|
||||||
enclose_area( scene::basic_node *Node );
|
enclose_area( scene::basic_node *Node );
|
||||||
// members
|
// members
|
||||||
|
|||||||
@@ -342,6 +342,10 @@ public:
|
|||||||
group( scene::group_handle Group );
|
group( scene::group_handle Group );
|
||||||
scene::group_handle
|
scene::group_handle
|
||||||
group() const;
|
group() const;
|
||||||
|
void
|
||||||
|
mark_dirty() { m_dirty = true; }
|
||||||
|
bool
|
||||||
|
dirty() const { return m_dirty; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// members
|
// members
|
||||||
@@ -351,6 +355,7 @@ protected:
|
|||||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||||
bool m_visible { true }; // visibility flag
|
bool m_visible { true }; // visibility flag
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
bool m_dirty { false };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// methods
|
// methods
|
||||||
|
|||||||
274
simulation.cpp
274
simulation.cpp
@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "particles.h"
|
#include "particles.h"
|
||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
#include "Train.h"
|
#include "Train.h"
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
namespace simulation {
|
namespace simulation {
|
||||||
|
|
||||||
@@ -37,18 +38,26 @@ powergridsource_table Powergrid;
|
|||||||
sound_table Sounds;
|
sound_table Sounds;
|
||||||
instance_table Instances;
|
instance_table Instances;
|
||||||
vehicle_table Vehicles;
|
vehicle_table Vehicles;
|
||||||
|
train_table Trains;
|
||||||
light_array Lights;
|
light_array Lights;
|
||||||
particle_manager Particles;
|
particle_manager Particles;
|
||||||
|
|
||||||
scene::basic_region *Region { nullptr };
|
scene::basic_region *Region { nullptr };
|
||||||
TTrain *Train { nullptr };
|
TTrain *Train { nullptr };
|
||||||
|
|
||||||
|
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
|
||||||
@@ -92,9 +101,7 @@ state_manager::init_scripting_interface() {
|
|||||||
void
|
void
|
||||||
state_manager::update( double const Deltatime, int Iterationcount ) {
|
state_manager::update( double const Deltatime, int Iterationcount ) {
|
||||||
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
|
// aktualizacja animacji krokiem FPS: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń
|
||||||
if (Deltatime == 0.0) {
|
if (Deltatime == 0.0) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const totaltime { Deltatime * Iterationcount };
|
auto const totaltime { Deltatime * Iterationcount };
|
||||||
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
|
// NOTE: we perform animations first, as they can determine factors like contact with powergrid
|
||||||
@@ -166,6 +173,261 @@ state_manager::update_scripting_interface() {
|
|||||||
*m_scriptinginterface.date = *date;
|
*m_scriptinginterface.date = *date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void state_manager::process_commands() {
|
||||||
|
command_data commanddata;
|
||||||
|
while( Commands.pop( commanddata, (uint32_t)command_target::simulation )) {
|
||||||
|
if (commanddata.command == user_command::consistreleaser) {
|
||||||
|
TDynamicObject *found_vehicle = simulation::Vehicles.find(commanddata.payload);
|
||||||
|
TDynamicObject *vehicle = found_vehicle;
|
||||||
|
|
||||||
|
while (vehicle) {
|
||||||
|
vehicle->MoverParameters->Hamulec->Releaser(commanddata.action != GLFW_RELEASE ? 1 : 0);
|
||||||
|
vehicle = vehicle->Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
vehicle = found_vehicle;
|
||||||
|
while (vehicle) {
|
||||||
|
vehicle->MoverParameters->Hamulec->Releaser(commanddata.action != GLFW_RELEASE ? 1 : 0);
|
||||||
|
vehicle = vehicle->Prev();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.action == GLFW_RELEASE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::debugtoggle)
|
||||||
|
DebugModeFlag = !DebugModeFlag;
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::pausetoggle) {
|
||||||
|
if( Global.iPause & 1 ) {
|
||||||
|
// jeśli pauza startowa
|
||||||
|
// odpauzowanie, gdy po wczytaniu miało nie startować
|
||||||
|
Global.iPause ^= 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Global.iPause ^= 2; // zmiana stanu zapauzowania
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::focuspauseset) {
|
||||||
|
if( commanddata.param1 == 1.0 )
|
||||||
|
Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie
|
||||||
|
else
|
||||||
|
Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::entervehicle) {
|
||||||
|
// przesiadka do innego pojazdu
|
||||||
|
if (!commanddata.freefly)
|
||||||
|
// only available in free fly mode
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TDynamicObject *dynamic = std::get<TDynamicObject *>( simulation::Region->find_vehicle( commanddata.location, 50, false, false ) );
|
||||||
|
|
||||||
|
if (!dynamic)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TTrain *train = simulation::Trains.find(dynamic->name());
|
||||||
|
if (train)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
train = new TTrain();
|
||||||
|
if (train->Init(dynamic)) {
|
||||||
|
simulation::Trains.insert(train);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete train;
|
||||||
|
train = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::queueevent) {
|
||||||
|
std::istringstream ss(commanddata.payload);
|
||||||
|
|
||||||
|
std::string event_name;
|
||||||
|
std::string vehicle_name;
|
||||||
|
std::getline(ss, event_name, '%');
|
||||||
|
std::getline(ss, vehicle_name, '%');
|
||||||
|
|
||||||
|
basic_event *ev = Events.FindEvent(event_name);
|
||||||
|
TDynamicObject *vehicle = nullptr;
|
||||||
|
if (!vehicle_name.empty())
|
||||||
|
vehicle = simulation::Vehicles.find(vehicle_name);
|
||||||
|
|
||||||
|
if (ev)
|
||||||
|
Events.AddToQuery(ev, vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::setlight) {
|
||||||
|
int light = std::round(commanddata.param1);
|
||||||
|
float state = commanddata.param2;
|
||||||
|
TAnimModel *model = simulation::Instances.find(commanddata.payload);
|
||||||
|
if (model)
|
||||||
|
model->LightSet(light, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::setdatetime) {
|
||||||
|
int yearday = std::round(commanddata.param1);
|
||||||
|
int minute = std::round(commanddata.param2 * 60.0);
|
||||||
|
simulation::Time.set_time(yearday, minute);
|
||||||
|
|
||||||
|
simulation::Environment.compute_season(yearday);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::setweather) {
|
||||||
|
Global.fFogEnd = commanddata.param1;
|
||||||
|
Global.Overcast = commanddata.param2;
|
||||||
|
|
||||||
|
simulation::Environment.compute_weather();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::settemperature) {
|
||||||
|
Global.AirTemperature = commanddata.param1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::insertmodel) {
|
||||||
|
std::istringstream ss(commanddata.payload);
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string data;
|
||||||
|
std::getline(ss, name, ':');
|
||||||
|
std::getline(ss, data, ':');
|
||||||
|
|
||||||
|
TAnimModel *model = simulation::State.create_model(data, name, commanddata.location);
|
||||||
|
simulation::State.create_eventlauncher("node -1 0 launcher eventlauncher 0 0 0 " + std::to_string(model->radius())
|
||||||
|
+ " none -10000.0 obstacle_collision end", name + "_snd", commanddata.location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::deletemodel) {
|
||||||
|
simulation::State.delete_model(simulation::Instances.find(commanddata.payload));
|
||||||
|
simulation::State.delete_eventlauncher(simulation::Events.FindEventlauncher(commanddata.payload + "_snd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::globalradiostop) {
|
||||||
|
simulation::Region->RadioStop( commanddata.location );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::resetconsist) {
|
||||||
|
TDynamicObject *found_vehicle = simulation::Vehicles.find(commanddata.payload);
|
||||||
|
TDynamicObject *vehicle = found_vehicle;
|
||||||
|
|
||||||
|
while (vehicle) {
|
||||||
|
if (vehicle->Next())
|
||||||
|
vehicle = vehicle->Next();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (vehicle) {
|
||||||
|
vehicle->MoverParameters->DamageFlag = 0;
|
||||||
|
vehicle->MoverParameters->EngDmgFlag = 0;
|
||||||
|
vehicle->MoverParameters->V = 0.0;
|
||||||
|
vehicle->MoverParameters->DistCounter = 0.0;
|
||||||
|
vehicle->MoverParameters->WheelFlat = 0.0;
|
||||||
|
vehicle->MoverParameters->AlarmChainFlag = false;
|
||||||
|
vehicle->MoverParameters->OffsetTrackH = 0.0;
|
||||||
|
vehicle->MoverParameters->OffsetTrackV = 0.0;
|
||||||
|
vehicle = vehicle->Prev();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::fillcompressor) {
|
||||||
|
TDynamicObject *vehicle = simulation::Vehicles.find(commanddata.payload);
|
||||||
|
vehicle->MoverParameters->CompressedVolume = 8.0f * vehicle->MoverParameters->VeselVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::dynamicmove) {
|
||||||
|
TDynamicObject *vehicle = simulation::Vehicles.find(commanddata.payload);
|
||||||
|
if (vehicle)
|
||||||
|
vehicle->move_set(commanddata.param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::consistteleport) {
|
||||||
|
std::istringstream ss(commanddata.payload);
|
||||||
|
|
||||||
|
std::string track_name;
|
||||||
|
std::string vehicle_name;
|
||||||
|
std::getline(ss, vehicle_name, '%');
|
||||||
|
std::getline(ss, track_name, '%');
|
||||||
|
|
||||||
|
TTrack *track = simulation::Paths.find(track_name);
|
||||||
|
TDynamicObject *vehicle = simulation::Vehicles.find(vehicle_name);
|
||||||
|
|
||||||
|
while (vehicle) {
|
||||||
|
if (vehicle->Next())
|
||||||
|
vehicle = vehicle->Next();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
double offset = 0.0;
|
||||||
|
|
||||||
|
while (vehicle) {
|
||||||
|
offset += vehicle->MoverParameters->Dim.L;
|
||||||
|
vehicle->place_on_track(track, offset, false);
|
||||||
|
vehicle = vehicle->Prev();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::spawntrainset) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::pullalarmchain) {
|
||||||
|
TDynamicObject *vehicle = simulation::Vehicles.find(commanddata.payload);
|
||||||
|
if (vehicle)
|
||||||
|
vehicle->MoverParameters->AlarmChainSwitch(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::sendaicommand) {
|
||||||
|
std::istringstream ss(commanddata.payload);
|
||||||
|
|
||||||
|
std::string vehicle_name;
|
||||||
|
std::string command;
|
||||||
|
std::getline(ss, vehicle_name, '%');
|
||||||
|
std::getline(ss, command, '%');
|
||||||
|
|
||||||
|
TDynamicObject *vehicle = simulation::Vehicles.find(vehicle_name);
|
||||||
|
glm::dvec3 location = commanddata.location;
|
||||||
|
if (vehicle && vehicle->Mechanik)
|
||||||
|
vehicle->Mechanik->PutCommand(command, commanddata.param1, commanddata.param2, &location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commanddata.command == user_command::quitsimulation) {
|
||||||
|
Application.queue_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DebugModeFlag) {
|
||||||
|
if (commanddata.command == user_command::timejump) {
|
||||||
|
Time.update(commanddata.param1);
|
||||||
|
}
|
||||||
|
else if (commanddata.command == user_command::timejumplarge) {
|
||||||
|
Time.update(20.0 * 60.0);
|
||||||
|
}
|
||||||
|
else if (commanddata.command == user_command::timejumpsmall) {
|
||||||
|
Time.update(5.0 * 60.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TAnimModel * state_manager::create_model(const std::string &src, const std::string &name, const glm::dvec3 &position) {
|
||||||
|
return m_serializer.create_model(src, name, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEventLauncher * state_manager::create_eventlauncher(const std::string &src, const std::string &name, const glm::dvec3 &position) {
|
||||||
|
return m_serializer.create_eventlauncher(src, name, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_manager::delete_model(TAnimModel *model) {
|
||||||
|
Region->erase(model);
|
||||||
|
Instances.purge(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_manager::delete_eventlauncher(TEventLauncher *launcher) {
|
||||||
|
launcher->dRadius = 0.0f; // disable it
|
||||||
|
}
|
||||||
|
|
||||||
// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel
|
// passes specified sound to all vehicles within range as a radio message broadcasted on specified channel
|
||||||
void
|
void
|
||||||
radio_message( sound_source *Message, int const Channel ) {
|
radio_message( sound_source *Message, int const Channel ) {
|
||||||
|
|||||||
26
simulation.h
26
simulation.h
@@ -27,9 +27,27 @@ public:
|
|||||||
update_clocks();
|
update_clocks();
|
||||||
void
|
void
|
||||||
update_scripting_interface();
|
update_scripting_interface();
|
||||||
// restores simulation data from specified file. returns: true on success, false otherwise
|
// process input commands
|
||||||
|
void
|
||||||
|
process_commands();
|
||||||
|
// create model from node string
|
||||||
|
TAnimModel *
|
||||||
|
create_model(const std::string &src, const std::string &name, const glm::dvec3 &position);
|
||||||
|
// create eventlauncher from node string
|
||||||
|
TEventLauncher *
|
||||||
|
create_eventlauncher(const std::string &src, const std::string &name, const glm::dvec3 &position);
|
||||||
|
// delete TAnimModel instance
|
||||||
|
void
|
||||||
|
delete_model(TAnimModel *model);
|
||||||
|
// delete TEventLauncher instance
|
||||||
|
void
|
||||||
|
delete_eventlauncher(TEventLauncher *launcher);
|
||||||
|
// 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
|
bool
|
||||||
deserialize( std::string const &Scenariofile );
|
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;
|
||||||
@@ -54,14 +72,18 @@ extern powergridsource_table Powergrid;
|
|||||||
extern sound_table Sounds;
|
extern sound_table Sounds;
|
||||||
extern instance_table Instances;
|
extern instance_table Instances;
|
||||||
extern vehicle_table Vehicles;
|
extern vehicle_table Vehicles;
|
||||||
|
extern train_table Trains;
|
||||||
extern light_array Lights;
|
extern light_array Lights;
|
||||||
extern particle_manager Particles;
|
extern particle_manager Particles;
|
||||||
|
|
||||||
extern scene::basic_region *Region;
|
extern scene::basic_region *Region;
|
||||||
extern TTrain *Train;
|
extern TTrain *Train;
|
||||||
|
|
||||||
|
extern uint16_t prev_train_id;
|
||||||
extern bool is_ready;
|
extern bool is_ready;
|
||||||
|
|
||||||
|
struct deserializer_state;
|
||||||
|
|
||||||
} // simulation
|
} // simulation
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ 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 );
|
||||||
@@ -40,36 +40,21 @@ state_serializer::deserialize( std::string const &Scenariofile ) {
|
|||||||
|
|
||||||
simulation::State.init_scripting_interface();
|
simulation::State.init_scripting_interface();
|
||||||
|
|
||||||
|
// 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( ( true == Global.file_binary_terrain )
|
|
||||||
&& ( 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; }
|
|
||||||
|
|
||||||
deserialize( scenarioparser, importscratchpad );
|
|
||||||
if( ( true == Global.file_binary_terrain )
|
|
||||||
&& ( 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;
|
if( false == state->input.ok() )
|
||||||
}
|
throw invalid_scenery_exception();
|
||||||
|
|
||||||
// restores class data from provided stream
|
|
||||||
void
|
|
||||||
state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
|
|
||||||
|
|
||||||
// prepare deserialization function table
|
// prepare deserialization function table
|
||||||
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
|
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
|
||||||
@@ -85,6 +70,7 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
|||||||
{ "config", &state_serializer::deserialize_config },
|
{ "config", &state_serializer::deserialize_config },
|
||||||
{ "description", &state_serializer::deserialize_description },
|
{ "description", &state_serializer::deserialize_description },
|
||||||
{ "event", &state_serializer::deserialize_event },
|
{ "event", &state_serializer::deserialize_event },
|
||||||
|
// { "lua", &state_serializer::deserialize_lua },
|
||||||
{ "firstinit", &state_serializer::deserialize_firstinit },
|
{ "firstinit", &state_serializer::deserialize_firstinit },
|
||||||
{ "group", &state_serializer::deserialize_group },
|
{ "group", &state_serializer::deserialize_group },
|
||||||
{ "endgroup", &state_serializer::deserialize_endgroup },
|
{ "endgroup", &state_serializer::deserialize_endgroup },
|
||||||
@@ -98,35 +84,37 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
|||||||
{ "time", &state_serializer::deserialize_time },
|
{ "time", &state_serializer::deserialize_time },
|
||||||
{ "trainset", &state_serializer::deserialize_trainset },
|
{ "trainset", &state_serializer::deserialize_trainset },
|
||||||
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
|
{ "endtrainset", &state_serializer::deserialize_endtrainset } };
|
||||||
using deserializefunctionbind = std::function<void()>;
|
|
||||||
std::unordered_map<
|
|
||||||
std::string,
|
|
||||||
deserializefunctionbind> functionmap;
|
|
||||||
for( auto &function : functionlist ) {
|
for( auto &function : functionlist ) {
|
||||||
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
|
state->functionmap.emplace( function.first, std::bind( function.second, this, std::ref( state->input ), std::ref( state->scratchpad ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// 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() >= 100 ) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
token = Input.getToken<std::string>();
|
token = Input.getToken<std::string>();
|
||||||
@@ -136,6 +124,18 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
|||||||
// manually perform scenario initialization
|
// manually perform scenario initialization
|
||||||
deserialize_firstinit( Input, Scratchpad );
|
deserialize_firstinit( Input, Scratchpad );
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
scene::Groups.update_map();
|
||||||
|
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
|
||||||
@@ -1072,6 +1072,60 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const {
|
|||||||
WriteLog( "Scenery data export done." );
|
WriteLog( "Scenery data export done." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAnimModel *state_serializer::create_model(const std::string &src, const std::string &name, const glm::dvec3 &position) {
|
||||||
|
cParser parser(src);
|
||||||
|
parser.getTokens(); // "node"
|
||||||
|
parser.getTokens(2); // ranges
|
||||||
|
|
||||||
|
scene::node_data nodedata;
|
||||||
|
parser >> nodedata.range_max >> nodedata.range_min;
|
||||||
|
|
||||||
|
parser.getTokens(2); // name, type
|
||||||
|
nodedata.name = name;
|
||||||
|
nodedata.type = "model";
|
||||||
|
|
||||||
|
scene::scratch_data scratch;
|
||||||
|
|
||||||
|
TAnimModel *cloned = deserialize_model(parser, scratch, nodedata);
|
||||||
|
|
||||||
|
if (!cloned)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
cloned->mark_dirty();
|
||||||
|
cloned->location(position);
|
||||||
|
simulation::Instances.insert(cloned);
|
||||||
|
simulation::Region->insert(cloned);
|
||||||
|
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEventLauncher *state_serializer::create_eventlauncher(const std::string &src, const std::string &name, const glm::dvec3 &position) {
|
||||||
|
cParser parser(src);
|
||||||
|
parser.getTokens(); // "node"
|
||||||
|
parser.getTokens(2); // ranges
|
||||||
|
|
||||||
|
scene::node_data nodedata;
|
||||||
|
parser >> nodedata.range_max >> nodedata.range_min;
|
||||||
|
|
||||||
|
parser.getTokens(2); // name, type
|
||||||
|
nodedata.name = name;
|
||||||
|
nodedata.type = "eventlauncher";
|
||||||
|
|
||||||
|
scene::scratch_data scratch;
|
||||||
|
|
||||||
|
TEventLauncher *launcher = deserialize_eventlauncher(parser, scratch, nodedata);
|
||||||
|
|
||||||
|
if (!launcher)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
launcher->Event1 = simulation::Events.FindEvent( launcher->asEvent1Name );
|
||||||
|
launcher->location(position);
|
||||||
|
simulation::Events.insert(launcher);
|
||||||
|
simulation::Region->insert(launcher);
|
||||||
|
|
||||||
|
return launcher;
|
||||||
|
}
|
||||||
|
|
||||||
} // simulation
|
} // simulation
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -14,21 +14,40 @@ 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
|
||||||
|
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
|
bool
|
||||||
deserialize( std::string const &Scenariofile );
|
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;
|
||||||
|
// create new model from node stirng
|
||||||
|
TAnimModel * create_model(std::string const &src, std::string const &name, const glm::dvec3 &position);
|
||||||
|
// create new eventlauncher from node stirng
|
||||||
|
TEventLauncher * create_eventlauncher(std::string const &src, std::string const &name, const glm::dvec3 &position);
|
||||||
|
|
||||||
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_assignment( cParser &Input, scene::scratch_data &Scratchpad );
|
void deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad );
|
||||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ scenario_time Time;
|
|||||||
} // simulation
|
} // simulation
|
||||||
|
|
||||||
void
|
void
|
||||||
scenario_time::init() {
|
scenario_time::init(std::time_t timestamp) {
|
||||||
|
|
||||||
char monthdaycounts[ 2 ][ 13 ] = {
|
char monthdaycounts[ 2 ][ 13 ] = {
|
||||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||||
@@ -32,7 +32,21 @@ scenario_time::init() {
|
|||||||
auto const requestedhour { ( requestedtime / 60 ) % 24 };
|
auto const requestedhour { ( requestedtime / 60 ) % 24 };
|
||||||
auto const requestedminute { requestedtime % 60 };
|
auto const requestedminute { requestedtime % 60 };
|
||||||
// cache requested elements, if any
|
// cache requested elements, if any
|
||||||
|
|
||||||
|
if( timestamp != 0 ) {
|
||||||
|
std::tm *tms = std::gmtime( ×tamp );
|
||||||
|
m_time.wYear = tms->tm_year + 1900;
|
||||||
|
m_time.wMonth = tms->tm_mon + 1;
|
||||||
|
m_time.wDayOfWeek = tms->tm_wday;
|
||||||
|
m_time.wDay = tms->tm_mday;
|
||||||
|
m_time.wHour = tms->tm_hour;
|
||||||
|
m_time.wMinute = tms->tm_min;
|
||||||
|
m_time.wSecond = tms->tm_sec;
|
||||||
|
m_time.wMilliseconds = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
::GetLocalTime( &m_time );
|
::GetLocalTime( &m_time );
|
||||||
|
}
|
||||||
|
|
||||||
if( Global.fMoveLight > 0.f ) {
|
if( Global.fMoveLight > 0.f ) {
|
||||||
// day and month of the year can be overriden by scenario setup
|
// day and month of the year can be overriden by scenario setup
|
||||||
@@ -192,6 +206,13 @@ scenario_time::julian_day() const {
|
|||||||
return JD;
|
return JD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scenario_time::set_time(int yearday, int minute) {
|
||||||
|
m_yearday = yearday;
|
||||||
|
daymonth(m_time.wDay, m_time.wMonth, m_time.wYear, m_yearday);
|
||||||
|
m_time.wHour = minute / 60;
|
||||||
|
m_time.wMinute = minute % 60;
|
||||||
|
}
|
||||||
|
|
||||||
// calculates day of week for provided date
|
// calculates day of week for provided date
|
||||||
int
|
int
|
||||||
scenario_time::day_of_week( int const Day, int const Month, int const Year ) const {
|
scenario_time::day_of_week( int const Day, int const Month, int const Year ) const {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public:
|
|||||||
scenario_time() {
|
scenario_time() {
|
||||||
m_time.wHour = 10; m_time.wMinute = 30; }
|
m_time.wHour = 10; m_time.wMinute = 30; }
|
||||||
void
|
void
|
||||||
init();
|
init(time_t timestamp = 0);
|
||||||
void
|
void
|
||||||
update( double const Deltatime );
|
update( double const Deltatime );
|
||||||
inline
|
inline
|
||||||
@@ -41,6 +41,8 @@ public:
|
|||||||
double
|
double
|
||||||
zone_bias() const {
|
zone_bias() const {
|
||||||
return m_timezonebias; }
|
return m_timezonebias; }
|
||||||
|
void
|
||||||
|
set_time(int yearday, int minute);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// converts provided time transition date to regular date
|
// converts provided time transition date to regular date
|
||||||
|
|||||||
41
sn_utils.cpp
41
sn_utils.cpp
@@ -38,6 +38,18 @@ int32_t sn_utils::ld_int32(std::istream &s)
|
|||||||
return reinterpret_cast<int32_t&>(v);
|
return reinterpret_cast<int32_t&>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deserialize little endian int64
|
||||||
|
int64_t sn_utils::ld_int64(std::istream &s)
|
||||||
|
{
|
||||||
|
uint8_t buf[8];
|
||||||
|
s.read((char*)buf, 8);
|
||||||
|
uint64_t v = ((uint64_t)buf[7] << 56) | ((uint64_t)buf[6] << 48) |
|
||||||
|
((uint64_t)buf[5] << 40) | ((uint64_t)buf[4] << 32) |
|
||||||
|
((uint64_t)buf[3] << 24) | ((uint64_t)buf[2] << 16) |
|
||||||
|
((uint64_t)buf[1] << 8) | (uint64_t)buf[0];
|
||||||
|
return reinterpret_cast<int64_t&>(v);
|
||||||
|
}
|
||||||
|
|
||||||
// deserialize little endian ieee754 float32
|
// deserialize little endian ieee754 float32
|
||||||
float sn_utils::ld_float32(std::istream &s)
|
float sn_utils::ld_float32(std::istream &s)
|
||||||
{
|
{
|
||||||
@@ -88,6 +100,14 @@ glm::dvec3 sn_utils::d_dvec3(std::istream& s)
|
|||||||
ld_float64(s) };
|
ld_float64(s) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 sn_utils::d_vec3( std::istream& s)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
ld_float32(s),
|
||||||
|
ld_float32(s),
|
||||||
|
ld_float32(s) };
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec4 sn_utils::d_vec4( std::istream& s)
|
glm::vec4 sn_utils::d_vec4( std::istream& s)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@@ -125,6 +145,20 @@ void sn_utils::ls_int32(std::ostream &s, int32_t v)
|
|||||||
s.write((char*)buf, 4);
|
s.write((char*)buf, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sn_utils::ls_int64(std::ostream &s, int64_t v)
|
||||||
|
{
|
||||||
|
uint8_t buf[8];
|
||||||
|
buf[0] = v;
|
||||||
|
buf[1] = v >> 8;
|
||||||
|
buf[2] = v >> 16;
|
||||||
|
buf[3] = v >> 24;
|
||||||
|
buf[4] = v >> 32;
|
||||||
|
buf[5] = v >> 40;
|
||||||
|
buf[6] = v >> 48;
|
||||||
|
buf[7] = v >> 56;
|
||||||
|
s.write((char*)buf, 8);
|
||||||
|
}
|
||||||
|
|
||||||
void sn_utils::ls_float32(std::ostream &s, float t)
|
void sn_utils::ls_float32(std::ostream &s, float t)
|
||||||
{
|
{
|
||||||
uint32_t v = reinterpret_cast<uint32_t&>(t);
|
uint32_t v = reinterpret_cast<uint32_t&>(t);
|
||||||
@@ -173,6 +207,13 @@ void sn_utils::s_dvec3(std::ostream &s, glm::dvec3 const &v)
|
|||||||
ls_float64(s, v.z);
|
ls_float64(s, v.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sn_utils::s_vec3(std::ostream &s, glm::vec3 const &v)
|
||||||
|
{
|
||||||
|
ls_float32(s, v.x);
|
||||||
|
ls_float32(s, v.y);
|
||||||
|
ls_float32(s, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
void sn_utils::s_vec4(std::ostream &s, glm::vec4 const &v)
|
void sn_utils::s_vec4(std::ostream &s, glm::vec4 const &v)
|
||||||
{
|
{
|
||||||
ls_float32(s, v.x);
|
ls_float32(s, v.x);
|
||||||
|
|||||||
@@ -10,20 +10,24 @@ public:
|
|||||||
static uint16_t ld_uint16(std::istream&);
|
static uint16_t ld_uint16(std::istream&);
|
||||||
static uint32_t ld_uint32(std::istream&);
|
static uint32_t ld_uint32(std::istream&);
|
||||||
static int32_t ld_int32(std::istream&);
|
static int32_t ld_int32(std::istream&);
|
||||||
|
static int64_t ld_int64(std::istream&);
|
||||||
static float ld_float32(std::istream&);
|
static float ld_float32(std::istream&);
|
||||||
static double ld_float64(std::istream&);
|
static double ld_float64(std::istream&);
|
||||||
static std::string d_str(std::istream&);
|
static std::string d_str(std::istream&);
|
||||||
static bool d_bool(std::istream&);
|
static bool d_bool(std::istream&);
|
||||||
static glm::dvec3 d_dvec3(std::istream&);
|
static glm::dvec3 d_dvec3(std::istream&);
|
||||||
|
static glm::vec3 d_vec3(std::istream&);
|
||||||
static glm::vec4 d_vec4(std::istream&);
|
static glm::vec4 d_vec4(std::istream&);
|
||||||
|
|
||||||
static void ls_uint16(std::ostream&, uint16_t);
|
static void ls_uint16(std::ostream&, uint16_t);
|
||||||
static void ls_uint32(std::ostream&, uint32_t);
|
static void ls_uint32(std::ostream&, uint32_t);
|
||||||
static void ls_int32(std::ostream&, int32_t);
|
static void ls_int32(std::ostream&, int32_t);
|
||||||
|
static void ls_int64(std::ostream&, int64_t);
|
||||||
static void ls_float32(std::ostream&, float);
|
static void ls_float32(std::ostream&, float);
|
||||||
static void ls_float64(std::ostream&, double);
|
static void ls_float64(std::ostream&, double);
|
||||||
static void s_str(std::ostream&, std::string);
|
static void s_str(std::ostream&, std::string);
|
||||||
static void s_bool(std::ostream&, bool);
|
static void s_bool(std::ostream&, bool);
|
||||||
static void s_dvec3(std::ostream&, glm::dvec3 const &);
|
static void s_dvec3(std::ostream&, glm::dvec3 const &);
|
||||||
|
static void s_vec3(std::ostream&, glm::vec3 const &);
|
||||||
static void s_vec4(std::ostream&, glm::vec4 const &);
|
static void s_vec4(std::ostream&, glm::vec4 const &);
|
||||||
};
|
};
|
||||||
@@ -194,7 +194,7 @@ sound_source::deserialize_mapping( cParser &Input ) {
|
|||||||
m_pitchvariation = (
|
m_pitchvariation = (
|
||||||
variation == 0.0f ?
|
variation == 0.0f ?
|
||||||
1.0f :
|
1.0f :
|
||||||
0.01f * static_cast<float>( Random( 100.0 - variation, 100.0 + variation ) ) );
|
0.01f * static_cast<float>( LocalRandom( 100.0 - variation, 100.0 + variation ) ) );
|
||||||
}
|
}
|
||||||
else if( key == "startoffset:" ) {
|
else if( key == "startoffset:" ) {
|
||||||
m_startoffset =
|
m_startoffset =
|
||||||
@@ -353,7 +353,7 @@ sound_source::play( int const Flags ) {
|
|||||||
|
|
||||||
// initialize emitter-specific pitch variation if it wasn't yet set
|
// initialize emitter-specific pitch variation if it wasn't yet set
|
||||||
if( m_pitchvariation == 0.f ) {
|
if( m_pitchvariation == 0.f ) {
|
||||||
m_pitchvariation = 0.01f * static_cast<float>( Random( 97.5, 102.5 ) );
|
m_pitchvariation = 0.01f * static_cast<float>( LocalRandom( 97.5, 102.5 ) );
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if( ( ( m_flags & sound_flags::exclusive ) != 0 )
|
if( ( ( m_flags & sound_flags::exclusive ) != 0 )
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Copyright (C) 2007-2014 Maciej Cierniak
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
bool DebugModeFlag = false;
|
bool DebugModeFlag = false;
|
||||||
bool FreeFlyModeFlag = false;
|
bool FreeFlyModeFlag = true;
|
||||||
bool EditorModeFlag = false;
|
bool EditorModeFlag = false;
|
||||||
bool DebugCameraFlag = false;
|
bool DebugCameraFlag = false;
|
||||||
bool DebugTractionFlag = false;
|
bool DebugTractionFlag = false;
|
||||||
@@ -106,8 +106,8 @@ bool ClearFlag( int &Flag, int const Value ) {
|
|||||||
|
|
||||||
double Random(double a, double b)
|
double Random(double a, double b)
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<> dis(a, b);
|
uint32_t val = Global.random_engine();
|
||||||
return dis(Global.random_engine);
|
return interpolate(a, b, (double)val / Global.random_engine.max());
|
||||||
}
|
}
|
||||||
|
|
||||||
double LocalRandom(double a, double b)
|
double LocalRandom(double a, double b)
|
||||||
|
|||||||
@@ -313,8 +313,8 @@ template <class Iterator_, class VecType_>
|
|||||||
void
|
void
|
||||||
bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) {
|
bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) {
|
||||||
|
|
||||||
Mincorner = VecType_( typename std::numeric_limits<VecType_::value_type>::max() );
|
Mincorner = VecType_( std::numeric_limits<typename VecType_::value_type>::max() );
|
||||||
Maxcorner = VecType_( typename std::numeric_limits<VecType_::value_type>::lowest() );
|
Maxcorner = VecType_( std::numeric_limits<typename VecType_::value_type>::lowest() );
|
||||||
|
|
||||||
std::for_each(
|
std::for_each(
|
||||||
First, Last,
|
First, Last,
|
||||||
|
|||||||
Reference in New Issue
Block a user