feat(chat): implement client-server chat messaging

Add protobuf definition for ChatMsg, new packet ID CHAT_MSG (4001), and
handle sending/receiving chat messages on both client and server side.
Wire up UI components (ChatBox, TextField) to allow message input and
display, including a message queue in ClientWorld for thread-safe
processing. Also add default initialization for ChatMessage::time.
This commit is contained in:
2026-07-18 20:29:14 +08:00
parent f4103e254e
commit 75f71a537f
19 changed files with 126 additions and 17 deletions

View File

@@ -6,6 +6,6 @@ namespace Cubed {
struct ChatMessage {
std::string player;
std::string text;
uint64_t time;
uint64_t time = 0;
};
} // namespace Cubed

View File

@@ -2,6 +2,7 @@
#include "Cubed/audio/audio_engine.hpp"
#include "Cubed/config.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/chat_message.hpp"
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/client_chunk.hpp"
#include "Cubed/gameplay/client_player.hpp"
@@ -102,6 +103,10 @@ public:
Config& get_config();
WorldScene& world_scene();
void set_direct_exit();
void receive_chat_message(ChatMsg& msg);
void send_chat_message(ChatMessage& message);
template <typename Fn>
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
m_ticktimers.emplace(
@@ -147,6 +152,7 @@ private:
tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue;
tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue;
tbb::concurrent_queue<PendingSound> m_pending_sound;
tbb::concurrent_queue<ChatMessage> m_message_queue;
std::deque<ChunkPos> m_dirty_queue;
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;

View File

@@ -61,6 +61,7 @@ enum class PacketEnum : uint16_t {
BLOCK_CHANGE_RSP = 3004,
S2C_CLEAR_ALL_CHUNKS = 3005,
UPDATE_TIME = 3006,
CHAT_MSG = 4001,
PING = 9001,
PONG = 9002
@@ -121,6 +122,9 @@ template <> constexpr uint16_t get_packet_id<Pong>() {
template <> constexpr uint16_t get_packet_id<PlayerWaterSound>() {
return std::to_underlying(PacketEnum::PLAYER_WATER_SOUND);
}
template <> constexpr uint16_t get_packet_id<ChatMsg>() {
return std::to_underlying(PacketEnum::CHAT_MSG);
}
template <typename T>
requires std::derived_from<T, google::protobuf::Message>

View File

@@ -80,6 +80,8 @@ public:
void handle_chunk_req(int task_id, const std::string& uuid, ChunkPos pos);
void handle_block_change(const BlockChangeReq& req);
void handle_chat_message(ChatMsg& msg);
int chunk_size() const;
template <typename Fn>
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
@@ -189,5 +191,7 @@ private:
std::atomic<std::shared_ptr<PriorityThreadPool>>& thread_pool,
int threads);
void send_server_stop();
void boardcast_message(const std::string& name, const std::string& message);
};
} // namespace Cubed

View File

@@ -35,6 +35,8 @@ public:
void set_error(std::string_view error);
void set_mouse(bool pause);
void set_chatting(bool chatting);
// Not thread safe
void handle_chat_message(ChatMessage& message);
private:
bool handle_mouse_move_event(const MouseMoveEvent& e) override;

View File

@@ -20,6 +20,8 @@ public:
ChatBox& set_width(float width);
ChatBox& set_show_lines(int lines);
ChatBox& set_spacing(float spacing);
ChatBox& clear_input();
std::string& get_input_text();
float width() const override;
float height() const override;
void set_d_image(TextureManager& m);

View File

@@ -28,13 +28,14 @@ public:
TextField& set_auto_scale(bool auto_scale);
TextField& set_app(App* app);
TextField& set_typing(bool typing);
TextField& clear_input();
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
bool handle_text_input_event(const TextInputEvent& e) override;
bool handle_key_event(const KeyEvent& e) override;
bool handle_window_resize_event(const WindowResizeEvent& e) override;
const std::string& input_text() const;
std::string& input_text();
template <typename F> TextField& set_on_finish(F&& f) {
m_on_finished = std::forward<F>(f);
return *this;

View File

@@ -21,6 +21,8 @@ public:
void set_chatting(bool chantting);
void add_chat_message(ChatMessage& message);
private:
bool handle_key_event(const KeyEvent& e) override;
WorldScene& m_scene;