From d43ca2a45ad53d6c4c926f63dba97f5ddaa668ce Mon Sep 17 00:00:00 2001 From: zbyv Date: Thu, 26 Mar 2026 23:14:50 +0100 Subject: [PATCH] Remote menus - serverside part --- CMakeLists.txt | 2 + src/game/remote_menu.cpp | 105 +++++++++++++++++++++++++++++++++++++++ src/game/remote_menu.hpp | 76 ++++++++++++++++++++++++++++ src/net/defs.hpp | 23 +++++++++ 4 files changed, 206 insertions(+) create mode 100644 src/game/remote_menu.cpp create mode 100644 src/game/remote_menu.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8485721..b3f7d98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,8 @@ set(SERVER_ONLY_SOURCES "src/game/player_character.cpp" "src/game/player.hpp" "src/game/player.cpp" + "src/game/remote_menu.hpp" + "src/game/remote_menu.cpp" "src/game/simple_entity.hpp" "src/game/simple_entity.cpp" "src/game/usable.hpp" diff --git a/src/game/remote_menu.cpp b/src/game/remote_menu.cpp new file mode 100644 index 0000000..628f859 --- /dev/null +++ b/src/game/remote_menu.cpp @@ -0,0 +1,105 @@ +#include "remote_menu.hpp" +#include "net/defs.hpp" + +game::RemoteMenuItem::RemoteMenuItem(RemoteMenu& menu, RemoteMenuItemType type, std::string text) : menu_(menu), type_(type) +{ + +} + +void game::RemoteMenuItem::SetText(std::string text) +{ + if (text == text_) + return; + + text_ = std::move(text); + text_synced_ = false; + menu_.items_synced_ = false; +} + +void game::RemoteMenuItem::SetSelection(std::string selection) +{ + if (selection == selection_) + return; + + selection_ = std::move(selection); + selection_synced_ = false; + menu_.items_synced_ = false; +} + +game::RemoteMenu::RemoteMenu(net::MenuId id) : id_(id) +{ +} + +game::RemoteMenuItem& game::RemoteMenu::AddItem(RemoteMenuItemType type, std::string text) +{ + auto item = std::make_unique(*this, type, std::move(text)); + auto& item_ref = *item; + + items_.push_back(std::move(item)); + synced_ = false; + + return item_ref; +} + + +void game::RemoteMenu::Update() +{ + if (synced_ && items_synced_) + return; + + // not synced at all, write full update + if (!synced_) + { + auto msg = BeginMenuMsg(net::MMSG_UPDATE); + + msg.Write(items_.size()); + for (auto& item : items_) + { + msg.Write(item->type_); + msg.Write(net::MenuItemText(item->text_)); + msg.Write(net::MenuItemSelection(item->selection_)); + + item->text_synced_ = true; + item->selection_synced_ = true; + } + + synced_ = true; + items_synced_ = true; + return; + } + + // some items want sync + if (!items_synced_) + { + for (size_t i = 0; i < items_.size(); ++i) + { + auto& item = *items_[i]; + + if (!item.text_synced_) + { + auto msg = BeginMenuMsg(net::MMSG_ITEM_UPDATE_TEXT); + msg.Write(i); + msg.Write(net::MenuItemText(item.text_)); + item.text_synced_ = true; + } + + if (!item.selection_synced_) + { + auto msg = BeginMenuMsg(net::MMSG_ITEM_UPDATE_SELECTION); + msg.Write(i); + msg.Write(net::MenuItemSelection(item.selection_)); + item.selection_synced_ = true; + } + } + + items_synced_ = true; + } +} + +net::OutMessage game::RemoteMenu::BeginMenuMsg(net::MenuMessageType type) +{ + auto msg = BeginMsg(net::MSG_REMOTEMENU); + msg.Write(id_); + msg.Write(type); + return msg; +} diff --git a/src/game/remote_menu.hpp b/src/game/remote_menu.hpp new file mode 100644 index 0000000..c65ce61 --- /dev/null +++ b/src/game/remote_menu.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include "net/defs.hpp" +#include "net/msg_producer.hpp" +#include "net/outmessage.hpp" + +namespace game +{ + +enum RemoteMenuItemType : uint8_t +{ + RM_LABEL, + RM_BUTTON, + RM_SELECT, +}; + +class RemoteMenu; +class RemoteMenuItem; + +using RemoteMenuClickCallback = std::function; +using RemoteMenuHoveredCallback = std::function; +using RemoteMenuSelectCallback = std::function; + +class RemoteMenuItem +{ +public: + RemoteMenuItem(RemoteMenu& menu, RemoteMenuItemType type, std::string text); + + void SetText(std::string text); + void SetSelection(std::string selection); + + void SetOnClick(RemoteMenuClickCallback on_click) { on_click_ = std::move(on_click); } + void SetOnSelect(RemoteMenuSelectCallback on_select) { on_select_ = std::move(on_select); } + void SetOnHovered(RemoteMenuHoveredCallback on_hovered) { on_hovered_ = std::move(on_hovered); } + +private: + RemoteMenu& menu_; + RemoteMenuItemType type_ = RM_LABEL; + std::string text_; + bool text_synced_ = false; + std::string selection_; + bool selection_synced_ = false; + + RemoteMenuClickCallback on_click_; + RemoteMenuSelectCallback on_select_; + RemoteMenuHoveredCallback on_hovered_; + + friend class RemoteMenu; +}; + +class RemoteMenu : public net::MsgProducer +{ +public: + RemoteMenu(net::MenuId id); + + RemoteMenuItem& AddItem(RemoteMenuItemType type, std::string text); + + void Update(); + +private: + net::OutMessage BeginMenuMsg(net::MenuMessageType type); + +private: + net::MenuId id_; + bool synced_ = false; + bool items_synced_ = false; + std::vector> items_; + int hovered_ = -1; + + friend class RemoteMenuItem; +}; + +} \ No newline at end of file diff --git a/src/net/defs.hpp b/src/net/defs.hpp index 04a1394..5ea8a89 100644 --- a/src/net/defs.hpp +++ b/src/net/defs.hpp @@ -37,6 +37,9 @@ enum MessageType : uint8_t // USETARGET ... MSG_USETARGET, + // REMOTEMENU ... + MSG_REMOTEMENU, + /*~~~~~~~~ Entity ~~~~~~~~*/ // ENTSPAWN data... MSG_ENTSPAWN, @@ -144,4 +147,24 @@ using TuningPartIdx = uint8_t; using UseTargetName = FixedStr<128>; using UseDelayQ = Quantized; +// remote menu + +enum MenuMessageType +{ + MMSG_CREATE, + MMSG_UPDATE, + MMSG_ITEM_UPDATE_TEXT, + MMSG_ITEM_UPDATE_SELECTION, + MMSG_CLOSE, +}; + +using MenuId = uint8_t; + +using MenuItemId = uint8_t; +using MenuItemCount = MenuItemId; + +using MenuItemText = FixedStr<64>; +using MenuItemSelection = FixedStr<64>; + + } // namespace net \ No newline at end of file