milek7/sim branch network code import

This commit is contained in:
tmj-fstate
2020-02-16 03:03:17 +01:00
parent 2ce3091e8f
commit 7a0c89f508
56 changed files with 2609 additions and 426 deletions

View File

@@ -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;
}