From 522a7514012da86f7b9643179f0763746f3b232e Mon Sep 17 00:00:00 2001 From: untodesu Date: Fri, 12 Sep 2025 16:15:32 +0500 Subject: Protocol and versioning changes --- game/client/gui/bother.cc | 8 +++- game/client/gui/bother.hh | 4 +- game/client/gui/play_menu.cc | 92 +++++++++++++++++++++++++++-------------- game/client/gui/window_title.cc | 11 +---- game/client/session.cc | 6 ++- 5 files changed, 76 insertions(+), 45 deletions(-) (limited to 'game/client') diff --git a/game/client/gui/bother.cc b/game/client/gui/bother.cc index 1bb7097..e87b9ff 100644 --- a/game/client/gui/bother.cc +++ b/game/client/gui/bother.cc @@ -2,6 +2,8 @@ #include "client/gui/bother.hh" +#include "core/version.hh" + #include "shared/protocol.hh" #include "client/globals.hh" @@ -29,10 +31,12 @@ static void on_status_response_packet(const protocol::StatusResponse& packet) gui::BotherResponseEvent event; event.identity = identity; event.is_server_unreachable = false; - event.protocol_version = packet.version; event.num_players = packet.num_players; event.max_players = packet.max_players; event.motd = packet.motd; + event.game_version_major = packet.game_version_major; + event.game_version_minor = packet.game_version_minor; + event.game_version_patch = packet.game_version_patch; globals::dispatcher.trigger(event); enet_peer_disconnect(packet.peer, protocol::CHANNEL); @@ -89,7 +93,7 @@ void gui::bother::update_late(void) if(0 < enet_host_service(bother_host, &enet_event, 0)) { if(enet_event.type == ENET_EVENT_TYPE_CONNECT) { protocol::StatusRequest packet; - packet.version = protocol::VERSION; + packet.game_version_major = version::major; protocol::send(enet_event.peer, protocol::encode(packet)); return; } diff --git a/game/client/gui/bother.hh b/game/client/gui/bother.hh index fc5bab4..75e56d1 100644 --- a/game/client/gui/bother.hh +++ b/game/client/gui/bother.hh @@ -5,9 +5,11 @@ namespace gui struct BotherResponseEvent final { unsigned int identity; bool is_server_unreachable; - std::uint32_t protocol_version; std::uint16_t num_players; std::uint16_t max_players; + std::uint32_t game_version_major; + std::uint32_t game_version_minor; + std::uint32_t game_version_patch; std::string motd; }; } // namespace gui diff --git a/game/client/gui/play_menu.cc b/game/client/gui/play_menu.cc index 5b9887e..ad85141 100644 --- a/game/client/gui/play_menu.cc +++ b/game/client/gui/play_menu.cc @@ -10,6 +10,8 @@ #include "core/utils/string.hh" +#include "core/version.hh" + #include "shared/protocol.hh" #include "client/gui/bother.hh" @@ -25,9 +27,8 @@ constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; constexpr static std::string_view DEFAULT_SERVER_NAME = "Voxelius Server"; constexpr static std::string_view SERVERS_TXT = "servers.txt"; -constexpr static std::string_view WARNING_TOAST = "[!]"; -constexpr static std::size_t MAX_SERVER_ITEM_NAME = 24; +constexpr static std::size_t MAX_SERVER_ITEM_NAME = 18; enum class item_status : unsigned int { UNKNOWN = 0x0000U, @@ -43,10 +44,12 @@ struct ServerStatusItem final { std::uint16_t port; // Things pulled from bother events - std::uint32_t protocol_version; std::uint16_t num_players; std::uint16_t max_players; std::string motd; + std::uint16_t game_version_major; + std::uint16_t game_version_minor; + std::uint16_t game_version_patch; // Unique identifier that monotonically // grows with each new server added and @@ -69,9 +72,6 @@ static std::string str_status_init; static std::string str_status_ping; static std::string str_status_fail; -static std::string str_outdated_client; -static std::string str_outdated_server; - static std::string input_itemname; static std::string input_hostname; static std::string input_password; @@ -106,11 +106,13 @@ static void add_new_server(void) { auto item = new ServerStatusItem(); item->port = protocol::PORT; - item->protocol_version = protocol::VERSION; item->max_players = UINT16_MAX; item->num_players = UINT16_MAX; item->identity = next_identity; item->status = item_status::UNKNOWN; + item->game_version_major = 0U; + item->game_version_minor = 0U; + item->game_version_patch = 0U; next_identity += 1U; @@ -202,9 +204,6 @@ static void on_language_set(const gui::LanguageSetEvent& event) str_status_init = gui::language::resolve("play_menu.status.init"); str_status_ping = gui::language::resolve("play_menu.status.ping"); str_status_fail = gui::language::resolve("play_menu.status.fail"); - - str_outdated_client = gui::language::resolve("play_menu.outdated_client"); - str_outdated_server = gui::language::resolve("play_menu.outdated_server"); } static void on_bother_response(const gui::BotherResponseEvent& event) @@ -212,18 +211,22 @@ static void on_bother_response(const gui::BotherResponseEvent& event) for(auto item : servers_deque) { if(item->identity == event.identity) { if(event.is_server_unreachable) { - item->protocol_version = 0U; item->num_players = UINT16_MAX; item->max_players = UINT16_MAX; item->motd = str_status_fail; item->status = item_status::FAILURE; + item->game_version_major = 0U; + item->game_version_minor = 0U; + item->game_version_patch = 0U; } else { - item->protocol_version = event.protocol_version; item->num_players = event.num_players; item->max_players = event.max_players; item->motd = event.motd; item->status = item_status::REACHED; + item->game_version_major = event.game_version_major; + item->game_version_minor = event.game_version_minor; + item->game_version_patch = event.game_version_patch; } break; @@ -264,30 +267,50 @@ static void layout_server_item(ServerStatusItem* item) if(item->status == item_status::REACHED) { auto stats = std::format("{}/{}", item->num_players, item->max_players); - auto stats_width = ImGui::CalcTextSize(stats.c_str(), stats.c_str() + stats.size()).x; - auto stats_pos = ImVec2(cursor.x + item_width - stats_width - padding.x, cursor.y + padding.y); + auto stats_size = ImGui::CalcTextSize(stats.c_str(), stats.c_str() + stats.size()); + auto stats_pos = ImVec2(cursor.x + item_width - stats_size.x - padding.x, cursor.y + padding.y); draw_list->AddText(stats_pos, ImGui::GetColorU32(ImGuiCol_TextDisabled), stats.c_str(), stats.c_str() + stats.size()); - if(item->protocol_version != protocol::VERSION) { - auto warning_size = ImGui::CalcTextSize(WARNING_TOAST.data(), WARNING_TOAST.data() + WARNING_TOAST.size()); - auto warning_pos = ImVec2(stats_pos.x - warning_size.x - padding.x - 4.0f * globals::gui_scale, cursor.y + padding.y); - auto warning_end = ImVec2(warning_pos.x + warning_size.x, warning_pos.y + warning_size.y); - draw_list->AddText(warning_pos, ImGui::GetColorU32(ImGuiCol_DragDropTarget), WARNING_TOAST.data(), - WARNING_TOAST.data() + WARNING_TOAST.size()); + auto major_version_mismatch = item->game_version_major != version::major; + auto minor_version_mismatch = item->game_version_minor != version::minor; + auto patch_version_mismatch = item->game_version_patch != version::patch; - if(ImGui::IsMouseHoveringRect(warning_pos, warning_end)) { - ImGui::BeginTooltip(); + ImU32 version_color; - if(item->protocol_version < protocol::VERSION) { - ImGui::TextUnformatted(str_outdated_server.c_str(), str_outdated_server.c_str() + str_outdated_server.size()); - } - else { - ImGui::TextUnformatted(str_outdated_client.c_str(), str_outdated_client.c_str() + str_outdated_client.size()); - } + if(major_version_mismatch || minor_version_mismatch || patch_version_mismatch) { + version_color = ImGui::GetColorU32(major_version_mismatch ? ImGuiCol_PlotLinesHovered : ImGuiCol_DragDropTarget); + } + else { + version_color = ImGui::GetColorU32(ImGuiCol_PlotHistogram); + } - ImGui::EndTooltip(); - } + ImGui::PushFont(globals::font_unscii8, 4.0f); + + std::string version_toast; + + if(item->game_version_major < 16U) { + // Pre v16.x.x servers didn't send minor and patch versions + // and also used a different versioning scheme; post v16 the + // major version became the protocol version and the semver lost the tweak part + version_toast = std::string("0.0.1"); + } + else { + version_toast = std::format("{}.{}.{}", item->game_version_major, item->game_version_minor, item->game_version_patch); } + + auto version_size = ImGui::CalcTextSize(version_toast.c_str(), version_toast.c_str() + version_toast.size()); + auto version_pos = ImVec2(stats_pos.x - version_size.x - padding.x - 4.0f * globals::gui_scale, + cursor.y + padding.y + 0.5f * (stats_size.y - version_size.y)); + auto version_end = ImVec2(version_pos.x + version_size.x, version_pos.y + version_size.y); + + auto outline_pos = ImVec2(version_pos.x - 2U * globals::gui_scale, version_pos.y - 2U * globals::gui_scale); + auto outline_end = ImVec2(version_end.x + 2U * globals::gui_scale, version_end.y + 2U * globals::gui_scale); + auto outline_thickness = math::max(1.0f, 0.5f * static_cast(globals::gui_scale)); + + draw_list->AddRect(outline_pos, outline_end, version_color, 0.0f, 0, outline_thickness); + draw_list->AddText(version_pos, version_color, version_toast.c_str(), version_toast.c_str() + version_toast.size()); + + ImGui::PopFont(); } ImU32 motd_color = {}; @@ -460,11 +483,13 @@ void gui::play_menu::init(void) auto item = new ServerStatusItem(); item->port = protocol::PORT; - item->protocol_version = protocol::VERSION; item->max_players = UINT16_MAX; item->num_players = UINT16_MAX; item->identity = next_identity; item->status = item_status::UNKNOWN; + item->game_version_major = version::major; + item->game_version_minor = version::minor; + item->game_version_patch = version::patch; next_identity += 1U; @@ -543,6 +568,11 @@ void gui::play_menu::layout(void) ImGui::EndTabItem(); } + if(ImGui::BeginTabItem("debug###play_menu.debug.child")) { + ImGui::ShowStyleEditor(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } diff --git a/game/client/gui/window_title.cc b/game/client/gui/window_title.cc index 6e2387c..2f96205 100644 --- a/game/client/gui/window_title.cc +++ b/game/client/gui/window_title.cc @@ -10,14 +10,5 @@ void gui::window_title::update(void) { - std::string title; - - if(globals::sound_ctx && globals::sound_dev) { - title = std::format("Voxelius {}: {}", version::semver, splash::get()); - } - else { - title = std::format("Voxelius {}: {} [NOSOUND]", version::semver, splash::get()); - } - - glfwSetWindowTitle(globals::window, title.c_str()); + glfwSetWindowTitle(globals::window, std::format("Voxelius {}: {}", version::semver, splash::get()).c_str()); } diff --git a/game/client/session.cc b/game/client/session.cc index 907b789..ce3d616 100644 --- a/game/client/session.cc +++ b/game/client/session.cc @@ -6,6 +6,8 @@ #include "core/math/crc64.hh" +#include "core/version.hh" + #include "shared/entity/head.hh" #include "shared/entity/player.hh" #include "shared/entity/transform.hh" @@ -284,11 +286,13 @@ void session::disconnect(std::string_view reason) void session::send_login_request(void) { protocol::LoginRequest packet; - packet.version = protocol::VERSION; + packet.game_version_major = version::major; packet.voxel_registry_checksum = world::voxel_registry::get_checksum(); packet.item_registry_checksum = world::item_registry::get_checksum(); packet.password_hash = server_password_hash; packet.username = client_game::username.get(); + packet.game_version_minor = version::minor; + packet.game_version_patch = version::patch; protocol::send(session::peer, protocol::encode(packet)); -- cgit