diff --git a/src/graphics/fixed_pipeline_renderer.cpp b/src/graphics/fixed_pipeline_renderer.cpp index c9c6acd4f..2a16bce4d 100644 --- a/src/graphics/fixed_pipeline_renderer.cpp +++ b/src/graphics/fixed_pipeline_renderer.cpp @@ -94,6 +94,9 @@ void FixedPipelineRenderer::render(float dt, bool is_loading) // Either render the gui, or the global elements of the race gui. GUIEngine::render(dt, is_loading); + if (irr_driver->getRenderNetworkDebug() && !is_loading) + irr_driver->renderNetworkDebug(); + // Render the profiler if(UserConfigParams::m_profiler_enabled) { @@ -113,4 +116,4 @@ std::unique_ptr FixedPipelineRenderer::createRenderTarget(const ir { return std::unique_ptr(new GL1RenderTarget(dimension, name)); } -#endif \ No newline at end of file +#endif diff --git a/src/graphics/fixed_pipeline_renderer.hpp b/src/graphics/fixed_pipeline_renderer.hpp index 623492482..7e3dc0d7b 100644 --- a/src/graphics/fixed_pipeline_renderer.hpp +++ b/src/graphics/fixed_pipeline_renderer.hpp @@ -31,13 +31,13 @@ class FixedPipelineRenderer: public AbstractRenderer { public: - void onLoadWorld() ; - void onUnloadWorld(); - + void onLoadWorld() OVERRIDE; + void onUnloadWorld() OVERRIDE; + void render(float dt, bool is_loading) OVERRIDE; - + std::unique_ptr createRenderTarget(const irr::core::dimension2du &dimension, - const std::string &name); + const std::string &name) OVERRIDE; }; #endif // !SERVER_ONLY diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 60ab1e6ae..95ee446bc 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -59,7 +59,9 @@ #include "main_loop.hpp" #include "modes/profile_world.hpp" #include "modes/world.hpp" +#include "network/network_config.hpp" #include "network/stk_host.hpp" +#include "network/stk_peer.hpp" #include "physics/physics.hpp" #include "scriptengine/property_animator.hpp" #include "states_screens/dialogs/confirm_resolution_dialog.hpp" @@ -142,6 +144,7 @@ const bool ALLOW_1280_X_720 = true; */ IrrDriver::IrrDriver() { + m_render_nw_debug = false; m_resolution_changing = RES_CHANGE_NONE; struct irr::SIrrlichtCreationParameters p; @@ -1909,7 +1912,10 @@ void IrrDriver::update(float dt, bool is_loading) video::SColor(255,100,101,140)); GUIEngine::render(dt, is_loading); - + if (m_render_nw_debug && !is_loading) + { + renderNetworkDebug(); + } m_video_driver->endScene(); } @@ -1932,6 +1938,59 @@ void IrrDriver::update(float dt, bool is_loading) #endif } // update +// ---------------------------------------------------------------------------- +void IrrDriver::renderNetworkDebug() +{ +#ifndef SERVER_ONLY + if (!NetworkConfig::get()->isNetworking() || + NetworkConfig::get()->isServer() || !STKHost::existHost()) + return; + + auto peer = STKHost::get()->getServerPeerForClient(); + if (!peer) + return; + + const core::dimension2d& screen_size = + m_video_driver->getScreenSize(); + core::rectbackground_rect( + (int)(0.02f * screen_size.Width), + (int)(0.3f * screen_size.Height), + (int)(0.98f * screen_size.Width), + (int)(0.6f * screen_size.Height)); + video::SColor color(0x80, 0xFF, 0xFF, 0xFF); + GL32_draw2DRectangle(color, background_rect); + std::string server_time = StringUtils::timeToString( + (float)STKHost::get()->getNetworkTimer() / 1000.0f, + /*precision*/2, /*display_minutes_if_zero*/true, + /*display_hours*/true); + + gui::IGUIFont* font = GUIEngine::getFont(); + unsigned height = font->getDimension(L"X").Height + 2; + background_rect.UpperLeftCorner.X += 5; + static video::SColor black = video::SColor(255, 0, 0, 0); + font->draw(StringUtils::insertValues( + L"Server time: %s Server state frequency: %d", + server_time.c_str(), NetworkConfig::get()->getStateFrequency()), + background_rect, black, false); + + background_rect.UpperLeftCorner.Y += height; + font->draw(StringUtils::insertValues( + L"Upload speed (KBps): %f Download speed (KBps): %f", + (float)STKHost::get()->getUploadSpeed() / 1024.0f, + (float)STKHost::get()->getDownloadSpeed() / 1024.0f, + NetworkConfig::get()->getStateFrequency()), background_rect, black, + false); + + background_rect.UpperLeftCorner.Y += height; + font->draw(StringUtils::insertValues( + L"Packet loss: %d Packet loss variance: %d", + peer->getENetPeer()->packetLoss, + peer->getENetPeer()->packetLossVariance, + NetworkConfig::get()->getStateFrequency()), background_rect, black, + false); +#endif +} // renderNetworkDebug + // ---------------------------------------------------------------------------- void IrrDriver::setRecording(bool val) { diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 0fdb49faa..20078de01 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -163,6 +163,7 @@ private: bool m_lightviz; bool m_boundingboxesviz; bool m_recording; + bool m_render_nw_debug; /** Background colour to reset a buffer. Can be changed by each track. */ irr::video::SColor m_clear_color; @@ -362,6 +363,12 @@ public: // ------------------------------------------------------------------------ void toggleBoundingBoxesViz() { m_boundingboxesviz = !m_boundingboxesviz; } // ------------------------------------------------------------------------ + void toggleRenderNetworkDebug() { m_render_nw_debug = !m_render_nw_debug; } + // ------------------------------------------------------------------------ + bool getRenderNetworkDebug() const { return m_render_nw_debug; } + // ------------------------------------------------------------------------ + void renderNetworkDebug(); + // ------------------------------------------------------------------------ bool getBoundingBoxesViz() { return m_boundingboxesviz; } // ------------------------------------------------------------------------ bool isRecording() const { return m_recording; } diff --git a/src/graphics/shader_based_renderer.cpp b/src/graphics/shader_based_renderer.cpp index 70d7d67db..c7513de9d 100644 --- a/src/graphics/shader_based_renderer.cpp +++ b/src/graphics/shader_based_renderer.cpp @@ -803,6 +803,8 @@ void ShaderBasedRenderer::render(float dt, bool is_loading) PROFILER_PUSH_CPU_MARKER("GUIEngine", 0x75, 0x75, 0x75); // Either render the gui, or the global elements of the race gui. GUIEngine::render(dt, is_loading); + if (irr_driver->getRenderNetworkDebug() && !is_loading) + irr_driver->renderNetworkDebug(); PROFILER_POP_CPU_MARKER(); } diff --git a/src/network/network_console.cpp b/src/network/network_console.cpp index ffa2e8408..2711b257b 100644 --- a/src/network/network_console.cpp +++ b/src/network/network_console.cpp @@ -42,6 +42,7 @@ void showHelp() std::cout << "kickban #, kick and ban # peer of STKHost." << std::endl; std::cout << "listpeers, List all peers with host ID and IP." << std::endl; std::cout << "listban, List IP ban list of server." << std::endl; + std::cout << "speedstats, Show upload and download speed." << std::endl; } // showHelp // ---------------------------------------------------------------------------- @@ -128,6 +129,13 @@ void mainLoop(STKHost* host) ban.second << std::endl; } } + else if (str == "speedstats") + { + std::cout << "Upload speed (KBps): " << + (float)host->getUploadSpeed() / 1024.0f << + " Download speed (KBps): " << + (float)host->getDownloadSpeed() / 1024.0f << std::endl; + } else { std::cout << "Unknown command: " << str << std::endl; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 7a4795cbd..f98c68421 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -258,7 +258,8 @@ void loadServerLobbyFromConfig() Log::fatal("ServerConfig", "Unsupported game mode"); int frequency_in_config = m_state_frequency; - if (frequency_in_config > stk_config->getPhysicsFPS()) + if (frequency_in_config <= 0 || + frequency_in_config > stk_config->getPhysicsFPS()) { Log::warn("ServerConfig", "Invalid %d state frequency which is larger " "than physics FPS %d, use default value.", diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 4b5cc8c3b..802c60dd9 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -700,6 +700,7 @@ void STKHost::mainLoop() } uint64_t last_ping_time = StkTime::getRealTimeMs(); + uint64_t last_update_speed_time = StkTime::getRealTimeMs(); uint64_t last_ping_time_update_for_client = StkTime::getRealTimeMs(); std::map ctp; while (m_exit_timeout.load() > StkTime::getRealTimeMs()) @@ -713,6 +714,17 @@ void STKHost::mainLoop() it++; } + if (last_update_speed_time < StkTime::getRealTimeMs()) + { + // Update upload / download speed per second + last_update_speed_time = StkTime::getRealTimeMs() + 1000; + m_upload_speed.store(getNetwork()->getENetHost()->totalSentData); + m_download_speed.store( + getNetwork()->getENetHost()->totalReceivedData); + getNetwork()->getENetHost()->totalSentData = 0; + getNetwork()->getENetHost()->totalReceivedData = 0; + } + auto sl = LobbyProtocol::get(); if (direct_socket && sl && sl->waitingForPlayers()) { diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 35e2547ed..002d062fe 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -140,6 +140,10 @@ private: std::atomic m_client_ping; + std::atomic m_upload_speed; + + std::atomic m_download_speed; + std::atomic m_network_timer; std::unique_ptr m_nts; @@ -339,7 +343,12 @@ public: { m_network_timer.store(StkTime::getRealTimeMs() - ticks); } // ------------------------------------------------------------------------ std::pair getAllPlayersTeamInfo() const; - + // ------------------------------------------------------------------------ + /* Return upload speed in bytes per second. */ + unsigned getUploadSpeed() const { return m_upload_speed.load(); } + // ------------------------------------------------------------------------ + /* Return download speed in bytes per second. */ + unsigned getDownloadSpeed() const { return m_download_speed.load(); } }; // class STKHost #endif // STK_HOST_HPP diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index aab861a8d..d16cec998 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -229,18 +229,18 @@ void OptionsScreenVideo::init() assert( full != NULL ); full->setState( UserConfigParams::m_fullscreen ); - LabelWidget* full_text = getWidget("fullscreenText"); - assert( full_text != NULL ); - CheckBoxWidget* rememberWinpos = getWidget("rememberWinpos"); assert( rememberWinpos != NULL ); rememberWinpos->setState(UserConfigParams::m_remember_window_location); rememberWinpos->setActive(!UserConfigParams::m_fullscreen); - +#ifdef DEBUG + LabelWidget* full_text = getWidget("fullscreenText"); + assert( full_text != NULL ); + LabelWidget* rememberWinposText = getWidget("rememberWinposText"); assert( rememberWinposText != NULL ); - +#endif // --- get resolution list from irrlicht the first time if (!m_inited) { diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index ac3bd6042..550874626 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -140,6 +140,7 @@ enum DebugMenuCommand DEBUG_SCRIPT_CONSOLE, DEBUG_RUN_CUTSCENE, DEBUG_TEXTURE_CONSOLE, + DEBUG_RENDER_NW_DEBUG, DEBUG_START_RECORDING, DEBUG_STOP_RECORDING }; // DebugMenuCommand @@ -849,6 +850,9 @@ bool handleContextMenuAction(s32 cmd_id) return false; }); break; + case DEBUG_RENDER_NW_DEBUG: + irr_driver->toggleRenderNetworkDebug(); + break; case DEBUG_START_RECORDING: irr_driver->setRecording(true); break; @@ -988,7 +992,7 @@ bool onEvent(const SEvent &event) mnu->addItem(L"Scripting console", DEBUG_SCRIPT_CONSOLE); mnu->addItem(L"Run cutscene(s)", DEBUG_RUN_CUTSCENE); mnu->addItem(L"Texture console", DEBUG_TEXTURE_CONSOLE); - + mnu->addItem(L"Network debugging", DEBUG_RENDER_NW_DEBUG); g_debug_menu_visible = true; irr_driver->showPointer(); }