diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index 50384120..e5018c92 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -444,6 +444,17 @@ class AdvancedSettingsWindow(ba.Window): maxwidth=430, ) + v -= 42 + self._show_game_ping_check_box = ConfigCheckBox( + parent=self._subcontainer, + position=(50, v), + size=(self._sub_width - 100, 30), + configkey='Show Ping', + displayname=ba.Lstr(value='Show InGame Ping'), + scale=1.0, + maxwidth=430, + ) + v -= 42 self._disable_camera_shake_check_box = ConfigCheckBox( parent=self._subcontainer, @@ -716,6 +727,8 @@ class AdvancedSettingsWindow(ba.Window): sel_name = 'Benchmarks' elif sel == self._kick_idle_players_check_box.widget: sel_name = 'KickIdlePlayers' + elif sel == self._show_game_ping_check_box.widget: + sel_name = 'ShowPing' elif sel == self._disable_camera_shake_check_box.widget: sel_name = 'DisableCameraShake' elif ( @@ -776,6 +789,8 @@ class AdvancedSettingsWindow(ba.Window): sel = self._benchmarks_button elif sel_name == 'KickIdlePlayers': sel = self._kick_idle_players_check_box.widget + elif sel_name == 'ShowPing': + sel = self._show_game_ping_check_box.widget elif sel_name == 'DisableCameraShake': sel = self._disable_camera_shake_check_box.widget elif ( diff --git a/src/ballistica/app/app_config.cc b/src/ballistica/app/app_config.cc index cf6f0b23..6446ca71 100644 --- a/src/ballistica/app/app_config.cc +++ b/src/ballistica/app/app_config.cc @@ -222,6 +222,7 @@ void AppConfig::SetupEntries() { bool_entries_[BoolID::kAlwaysUseInternalKeyboard] = BoolEntry("Always Use Internal Keyboard", g_buildconfig.iircade_build()); bool_entries_[BoolID::kShowFPS] = BoolEntry("Show FPS", false); + bool_entries_[BoolID::kShowPing] = BoolEntry("Show Ping", false); bool_entries_[BoolID::kTVBorder] = BoolEntry("TV Border", g_platform->IsRunningOnTV()); bool_entries_[BoolID::kKeyboardP2Enabled] = diff --git a/src/ballistica/app/app_config.h b/src/ballistica/app/app_config.h index 9a970b4a..bfd3e3ee 100644 --- a/src/ballistica/app/app_config.h +++ b/src/ballistica/app/app_config.h @@ -61,6 +61,7 @@ class AppConfig { kKickIdlePlayers, kAlwaysUseInternalKeyboard, kShowFPS, + kShowPing, kTVBorder, kKeyboardP2Enabled, kEnablePackageMods, diff --git a/src/ballistica/graphics/graphics.cc b/src/ballistica/graphics/graphics.cc index d2fd216d..e5a397ed 100644 --- a/src/ballistica/graphics/graphics.cc +++ b/src/ballistica/graphics/graphics.cc @@ -277,6 +277,47 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) { c.Submit(); } + if (show_ping_) { + float ping{}; + char ping_str[32]; + if (ConnectionToHost* connection_to_host = + g_logic->connections()->connection_to_host()) { + if (connection_to_host->can_communicate()) { + ping = connection_to_host->current_ping(); + snprintf(ping_str, sizeof(ping_str), "%.0f ms", ping); + if (ping_str != ping_string_) { + ping_string_ = ping_str; + if (!ping_text_group_.exists()) { + ping_text_group_ = Object::New(); + } + ping_text_group_->SetText(ping_string_); + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0.5f, 0.9f, 0.5f, 1.0f); + if (ping > 100.0f) { + c.SetColor(0.8f, 0.8f, 0.0f, 1.0f); + } + if (ping > 500.0f) { + c.SetColor(0.9f, 0.2f, 0.2f, 1.0f); + } + + int text_elem_count = ping_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(ping_text_group_->GetElementTexture(e)); + c.SetFlatness(1.0f); + c.PushTransform(); + c.Translate(14.0f + (show_fps_ ? 30.0f : 0.0f), 0.1f, + kScreenMessageZDepth); + c.Scale(0.7f, 0.7f); + c.DrawMesh(ping_text_group_->GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + } + if (show_net_info_) { char net_info_str[128]; int64_t in_count = 0; @@ -287,8 +328,6 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) { int64_t out_size_compressed = 0; int64_t resends = 0; int64_t resends_size = 0; - bool do_ping = false; - float ping{}; bool show = false; // Add in/out data for any host connection. @@ -304,7 +343,6 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) { outCount += connection_to_host->GetMessagesOutPerSecond(); resends += connection_to_host->GetMessageResendsPerSecond(); resends_size += connection_to_host->GetBytesResentPerSecond(); - ping = connection_to_host->average_ping(); } else { int connected_count = 0; for (auto&& i : g_logic->connections()->connections_to_clients()) { @@ -321,40 +359,21 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) { outCount += client->GetMessagesOutPerSecond(); resends += client->GetMessageResendsPerSecond(); resends_size += client->GetBytesResentPerSecond(); - ping += client->average_ping(); - } - - // We want an average for ping. - if (connected_count > 0) { - ping /= static_cast(connected_count); } } if (show) { - if (do_ping) { - snprintf(net_info_str, sizeof(net_info_str), - "ping: %f\nin: %d/%d/%d\nout: %d/%d/%d\nrpt: " - "%d/%d", - ping, static_cast_check_fit(in_size), - static_cast_check_fit(in_size_compressed), - static_cast_check_fit(in_count), - static_cast_check_fit(out_size), - static_cast_check_fit(out_size_compressed), - static_cast_check_fit(outCount), - static_cast_check_fit(resends_size), - static_cast_check_fit(resends)); - } else { - snprintf(net_info_str, sizeof(net_info_str), - "in: %d/%d/%d\nout: %d/%d/%d\nrpt: %d/%d", - static_cast_check_fit(in_size), - static_cast_check_fit(in_size_compressed), - static_cast_check_fit(in_count), - static_cast_check_fit(out_size), - static_cast_check_fit(out_size_compressed), - static_cast_check_fit(outCount), - static_cast_check_fit(resends_size), - static_cast_check_fit(resends)); - } + snprintf(net_info_str, sizeof(net_info_str), + "in: %d/%d/%d\nout: %d/%d/%d\nrpt: %d/%d", + static_cast_check_fit(in_size), + static_cast_check_fit(in_size_compressed), + static_cast_check_fit(in_count), + static_cast_check_fit(out_size), + static_cast_check_fit(out_size_compressed), + static_cast_check_fit(outCount), + static_cast_check_fit(resends_size), + static_cast_check_fit(resends)); + net_info_str[sizeof(net_info_str) - 1] = 0; // in case we overran.. if (net_info_str != net_info_string_) { net_info_string_ = net_info_str; @@ -371,9 +390,7 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) { c.SetTexture(net_info_text_group_->GetElementTexture(e)); c.SetFlatness(1.0f); c.PushTransform(); - c.Translate(4.0f, - (show_fps_ ? 66.0f : 40.0f) + (do_ping ? 17.0f : 0.0f), - kScreenMessageZDepth); + c.Translate(4.0f, (show_fps_ ? 66.0f : 40.0f), kScreenMessageZDepth); c.Scale(0.7f, 0.7f); c.DrawMesh(net_info_text_group_->GetElementMesh(e)); c.PopTransform(); diff --git a/src/ballistica/graphics/graphics.h b/src/ballistica/graphics/graphics.h index 8d8c309f..5c04ce3c 100644 --- a/src/ballistica/graphics/graphics.h +++ b/src/ballistica/graphics/graphics.h @@ -206,7 +206,7 @@ class Graphics { float upper_top) -> void; auto ReleaseFadeEndCommand() -> void; auto set_show_fps(bool val) -> void { show_fps_ = val; } - + auto set_show_ping(bool val) -> void { show_ping_ = val; } // FIXME - move to graphics_server auto set_tv_border(bool val) -> void { assert(InLogicThread()); @@ -358,11 +358,13 @@ class Graphics { Object::Ref progress_bar_top_mesh_; Object::Ref load_dot_mesh_; Object::Ref fps_text_group_; + Object::Ref ping_text_group_; Object::Ref net_info_text_group_; Object::Ref shadow_blotch_mesh_; Object::Ref shadow_blotch_soft_mesh_; Object::Ref shadow_blotch_soft_obj_mesh_; std::string fps_string_; + std::string ping_string_; std::string net_info_string_; std::vector blotch_indices_; std::vector blotch_verts_; @@ -371,6 +373,7 @@ class Graphics { std::vector blotch_soft_obj_indices_; std::vector blotch_soft_obj_verts_; bool show_fps_{}; + bool show_ping_{}; bool show_net_info_{}; bool tv_border_{}; bool floor_reflection_{}; diff --git a/src/ballistica/logic/connection/connection.cc b/src/ballistica/logic/connection/connection.cc index ec901c52..2e34e0b0 100644 --- a/src/ballistica/logic/connection/connection.cc +++ b/src/ballistica/logic/connection/connection.cc @@ -24,6 +24,9 @@ const int kPacketPruneTime = 10000; // How long to go between pruning our packets. const int kPacketPruneInterval = 1000; +// How long to go between updating current ping. +const int kPingUpdateInterval = 2000; + Connection::Connection() { // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) creation_time_ = last_average_update_time_ = GetRealTime(); @@ -84,11 +87,11 @@ void Connection::HandleResends(millisecs_t real_time, if (j != out_messages_.end()) { ReliableMessageOut& msg(j->second); if (!msg.acked) { - float smoothing = 0.95f; - average_ping_ = - smoothing * average_ping_ - + (1.0f - smoothing) - * static_cast(real_time - msg.first_send_time); + // Dont update too fast. + if (real_time - last_ping_update_time_ > kPingUpdateInterval) { + current_ping_ = static_cast(real_time - msg.first_send_time); + last_ping_update_time_ = real_time; + } } msg.acked = true; } @@ -385,6 +388,15 @@ void Connection::Update() { SendGamePacket(data); } + if (can_communicate() + && real_time - last_ping_update_time_ > kPingUpdateInterval + 1000) { + // Send a reliable message if ping not updated in a while. + + std::vector data(1); + data[0] = BA_PACKET_SIMPLE_PING; + SendReliableMessage(data); + } + // Occasionally prune our in and out messages. if (real_time - last_prune_time_ > kPacketPruneInterval) { last_prune_time_ = real_time; diff --git a/src/ballistica/logic/connection/connection.h b/src/ballistica/logic/connection/connection.h index b130ed21..60352ada 100644 --- a/src/ballistica/logic/connection/connection.h +++ b/src/ballistica/logic/connection/connection.h @@ -63,7 +63,7 @@ class Connection : public Object { auto GetBytesResentPerSecond() const -> int64_t { return last_resend_bytes_out_; } - auto average_ping() const -> float { return average_ping_; } + auto current_ping() const -> float { return current_ping_; } auto can_communicate() const -> bool { return can_communicate_; } auto peer_spec() const -> const PlayerSpec& { return peer_spec_; } void HandleGamePacketCompressed(const std::vector& data); @@ -106,7 +106,7 @@ class Connection : public Object { // Leaf classes should set this when they start dying. // This prevents any SendGamePacketCompressed() calls from happening. bool connection_dying_{}; - float average_ping_{}; + float current_ping_{}; int64_t last_resend_bytes_out_{}; int64_t last_bytes_out_{}; int64_t last_bytes_out_compressed_{}; @@ -132,7 +132,7 @@ class Connection : public Object { bool errored_{}; millisecs_t last_prune_time_{}; millisecs_t last_ack_send_time_{}; - + millisecs_t last_ping_update_time_{}; // These are explicitly 16 bit values. uint16_t next_out_message_num_ = kFirstConnectionStateNum; uint16_t next_out_unreliable_message_num_{}; diff --git a/src/ballistica/logic/logic.cc b/src/ballistica/logic/logic.cc index 4ebe931d..a502d320 100644 --- a/src/ballistica/logic/logic.cc +++ b/src/ballistica/logic/logic.cc @@ -1292,6 +1292,8 @@ void Logic::ApplyConfig() { chat_muted_ = g_app_config->Resolve(AppConfig::BoolID::kChatMuted); g_graphics->set_show_fps(g_app_config->Resolve(AppConfig::BoolID::kShowFPS)); + g_graphics->set_show_ping( + g_app_config->Resolve(AppConfig::BoolID::kShowPing)); // Set tv border (for both client and server). // FIXME: this should exist either on the client or the server; not both.