mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
milek7/sim branch network code import
This commit is contained in:
263
application.cpp
263
application.cpp
@@ -43,6 +43,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma comment (lib, "dbghelp.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 NvOptimusEnablement = 0x00000001; }
|
||||
|
||||
@@ -65,19 +70,14 @@ extern WNDPROC BaseWindowProc;
|
||||
// user input callbacks
|
||||
|
||||
void focus_callback( GLFWwindow *window, int focus ) {
|
||||
if( Global.bInactivePause ) // jeśli ma być pauzowanie okna w tle
|
||||
if( focus )
|
||||
Global.iPause &= ~4; // odpauzowanie, gdy jest na pierwszym planie
|
||||
else
|
||||
Global.iPause |= 4; // włączenie pauzy, gdy nieaktywy
|
||||
Application.on_focus_change(focus != 0);
|
||||
}
|
||||
|
||||
void window_resize_callback( GLFWwindow *window, int w, int h ) {
|
||||
// NOTE: we have two variables which basically do the same thing as we don't have dynamic fullscreen toggle
|
||||
// TBD, TODO: merge them?
|
||||
Global.iWindowWidth = w;
|
||||
Global.iWindowHeight = h;
|
||||
Global.fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use
|
||||
Global.iWindowHeight = 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 );
|
||||
}
|
||||
|
||||
void char_callback(GLFWwindow *window, unsigned int c)
|
||||
{
|
||||
Application.on_char(c);
|
||||
}
|
||||
|
||||
// public:
|
||||
|
||||
int
|
||||
@@ -117,10 +122,10 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
|
||||
WriteLog( "For online documentation and additional files refer to: http://eu07.pl" );
|
||||
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
|
||||
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
|
||||
WriteLog( "Starting MaSzyna rail vehicle simulator (release: " + Global.asVersion + ")" );
|
||||
WriteLog( "For online documentation and additional files refer to: http://eu07.pl" );
|
||||
WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, "
|
||||
"ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" );
|
||||
|
||||
if( ( result = init_glfw() ) != 0 ) {
|
||||
return result;
|
||||
@@ -140,9 +145,28 @@ eu07_application::init( int Argc, char *Argv[] ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!init_network())
|
||||
return -1;
|
||||
|
||||
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
|
||||
eu07_application::run() {
|
||||
|
||||
@@ -151,11 +175,125 @@ eu07_application::run() {
|
||||
{
|
||||
Timer::subsystem.mainloop_total.start();
|
||||
|
||||
if( !m_modes[ m_modestack.top() ]->update() )
|
||||
break;
|
||||
// -------------------------------------------------------------------
|
||||
// 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())
|
||||
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())
|
||||
break;
|
||||
return 0;
|
||||
|
||||
glfwPollEvents();
|
||||
|
||||
@@ -164,10 +302,15 @@ eu07_application::run() {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// issues request for a worker thread to perform specified task. returns: true if task was scheduled
|
||||
@@ -199,8 +342,12 @@ eu07_application::release_python_lock() {
|
||||
|
||||
void
|
||||
eu07_application::exit() {
|
||||
for (auto &mode : m_modes)
|
||||
mode.reset();
|
||||
|
||||
SafeDelete( simulation::Train );
|
||||
m_network.reset();
|
||||
|
||||
// SafeDelete( simulation::Train );
|
||||
SafeDelete( simulation::Region );
|
||||
|
||||
ui_layer::shutdown();
|
||||
@@ -208,8 +355,11 @@ eu07_application::exit() {
|
||||
for( auto *window : m_windows ) {
|
||||
glfwDestroyWindow( window );
|
||||
}
|
||||
glfwTerminate();
|
||||
m_taskqueue.exit();
|
||||
glfwTerminate();
|
||||
|
||||
if (!Global.exec_on_exit.empty())
|
||||
system(Global.exec_on_exit.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -222,7 +372,6 @@ eu07_application::render_ui() {
|
||||
|
||||
bool
|
||||
eu07_application::pop_mode() {
|
||||
|
||||
if( m_modestack.empty() ) { return false; }
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
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 );
|
||||
}
|
||||
|
||||
void eu07_application::on_char( unsigned int const Char ) {
|
||||
|
||||
if( m_modestack.empty() ) { return; }
|
||||
|
||||
m_modes[ m_modestack.top() ]->on_char( Char );
|
||||
}
|
||||
|
||||
void
|
||||
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 );
|
||||
}
|
||||
|
||||
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 *
|
||||
eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership , bool share_ctx) {
|
||||
|
||||
@@ -373,7 +537,7 @@ eu07_application::window(int const Windowindex, bool visible, int width, int hei
|
||||
|
||||
// private:
|
||||
GLFWmonitor* eu07_application::find_monitor(const std::string &str) const {
|
||||
int monitor_count;
|
||||
int monitor_count;
|
||||
GLFWmonitor **monitors = glfwGetMonitors(&monitor_count);
|
||||
|
||||
for (size_t i = 0; i < monitor_count; i++) {
|
||||
@@ -394,17 +558,21 @@ std::string eu07_application::describe_monitor(GLFWmonitor *monitor) const {
|
||||
return name + ":" + std::to_string(x) + "," + std::to_string(y);
|
||||
}
|
||||
|
||||
// private:
|
||||
|
||||
void
|
||||
eu07_application::init_debug() {
|
||||
|
||||
#if defined(_MSC_VER) && defined (_DEBUG)
|
||||
// memory leaks
|
||||
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
|
||||
/*
|
||||
// floating point operation errors
|
||||
auto state { _clearfp() };
|
||||
state = _control87( 0, 0 );
|
||||
// this will turn on FPE for #IND and zerodiv
|
||||
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
|
||||
*/
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
::SetUnhandledExceptionFilter( unhandled_handler );
|
||||
@@ -417,7 +585,11 @@ eu07_application::init_files() {
|
||||
#ifdef _WIN32
|
||||
DeleteFile( "log.txt" );
|
||||
DeleteFile( "errors.txt" );
|
||||
_mkdir( "logs" );
|
||||
CreateDirectory( "logs", NULL );
|
||||
#elif __unix__
|
||||
unlink("log.txt");
|
||||
unlink("errors.txt");
|
||||
mkdir("logs", 0755);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -425,10 +597,12 @@ int
|
||||
eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||
|
||||
Global.LoadIniFile( "eu07.ini" );
|
||||
#ifdef _WIN32
|
||||
if( ( Global.iWriteLogEnabled & 2 ) != 0 ) {
|
||||
// show output console if requested
|
||||
AllocConsole();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' );
|
||||
Global.ExecutableName =
|
||||
@@ -486,7 +660,7 @@ eu07_application::init_settings( int Argc, char *Argv[] ) {
|
||||
}
|
||||
else if( token == "-v" ) {
|
||||
if( i + 1 < Argc ) {
|
||||
Global.asHumanCtrlVehicle = ToLower( Argv[ ++i ] );
|
||||
Global.local_start_vehicle = ToLower( Argv[ ++i ] );
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -588,6 +762,7 @@ eu07_application::init_callbacks() {
|
||||
glfwSetMouseButtonCallback( window, mouse_button_callback );
|
||||
glfwSetKeyCallback( window, key_callback );
|
||||
glfwSetScrollCallback( window, scroll_callback );
|
||||
glfwSetCharCallback(window, char_callback);
|
||||
glfwSetWindowFocusCallback( window, focus_callback );
|
||||
{
|
||||
int width, height;
|
||||
@@ -668,7 +843,12 @@ eu07_application::init_data() {
|
||||
|
||||
int
|
||||
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,
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user