feat(chat): add colored system messages for player join/exit

This commit is contained in:
2026-07-20 18:09:24 +08:00
parent 7e6f48ff07
commit 4d2b87bfcb
8 changed files with 67 additions and 8 deletions

View File

@@ -1,11 +1,15 @@
#pragma once #pragma once
#include "Cubed/ui/color.hpp"
#include <cstdint> #include <cstdint>
#include <string> #include <string>
namespace Cubed { namespace Cubed {
struct ChatMessage { struct ChatMessage {
std::string player; std::string player;
std::string text; std::string text;
Color color;
bool system_msg = false;
uint64_t time = 0; uint64_t time = 0;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -11,6 +11,7 @@
#include "Cubed/tools/priority_thread_pool.hpp" #include "Cubed/tools/priority_thread_pool.hpp"
#include "Cubed/tools/recent_queue.hpp" #include "Cubed/tools/recent_queue.hpp"
#include "Cubed/tools/thread_pool.hpp" #include "Cubed/tools/thread_pool.hpp"
#include "Cubed/ui/color.hpp"
#include "world/block_change.pb.h" #include "world/block_change.pb.h"
#include <absl/container/flat_hash_set.h> #include <absl/container/flat_hash_set.h>
@@ -192,6 +193,7 @@ private:
int threads); int threads);
void send_server_stop(); void send_server_stop();
void boardcast_message(const std::string& name, const std::string& message); void boardcast_message(const std::string& name, const std::string& message,
Color color = Color::WHITE, bool system_msg = false);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -6,7 +6,7 @@
namespace Cubed { namespace Cubed {
enum class Color { enum class Color {
BLACK, BLACK = 0,
WHITE, WHITE,
RED, RED,
GREEN, GREEN,
@@ -21,6 +21,39 @@ enum class Color {
BROWN BROWN
}; };
inline constexpr Color color_from_int(int i) {
switch (i) {
case std::to_underlying(Color::BLACK):
return Color::BLACK;
case std::to_underlying(Color::WHITE):
return Color::WHITE;
case std::to_underlying(Color::RED):
return Color::RED;
case std::to_underlying(Color::GREEN):
return Color::GREEN;
case std::to_underlying(Color::BLUE):
return Color::BLUE;
case std::to_underlying(Color::YELLOW):
return Color::YELLOW;
case std::to_underlying(Color::CYAN):
return Color::CYAN;
case std::to_underlying(Color::MAGENTA):
return Color::MAGENTA;
case std::to_underlying(Color::GRAY):
return Color::GRAY;
case std::to_underlying(Color::ORANGE):
return Color::ORANGE;
case std::to_underlying(Color::PURPLE):
return Color::PURPLE;
case std::to_underlying(Color::PINK):
return Color::PINK;
case std::to_underlying(Color::BROWN):
return Color::BROWN;
default:
return Color::WHITE;
}
}
inline constexpr glm::vec4 color_value(Color color) { inline constexpr glm::vec4 color_value(Color color) {
using glm::vec4; using glm::vec4;

View File

@@ -752,7 +752,10 @@ void ClientWorld::request_exit() {
} }
void ClientWorld::receive_chat_message(ChatMsg& msg) { void ClientWorld::receive_chat_message(ChatMsg& msg) {
m_message_queue.emplace(msg.name(), msg.msg(), Tools::get_time_ticks()); Color color = color_from_int(msg.color());
m_message_queue.emplace(msg.name(), msg.msg(), color, msg.system_msg(),
Tools::get_time_ticks());
} }
void ClientWorld::receive_voice_message(VoiceMsg& msg) { void ClientWorld::receive_voice_message(VoiceMsg& msg) {

View File

@@ -681,19 +681,25 @@ void ServerWorld::handle_player_login(const std::string& name,
rsp->set_success(true); rsp->set_success(true);
rsp->set_uuid(uuid); rsp->set_uuid(uuid);
session->send(make_packet(*rsp), 0); session->send(make_packet(*rsp), 0);
boardcast_message("Server", std::format("Player {} Join Game", name),
Color::YELLOW, true);
} }
void ServerWorld::handle_player_exit(const std::string& uuid) { void ServerWorld::handle_player_exit(const std::string& uuid) {
std::shared_ptr<Session> exit_session; std::shared_ptr<Session> exit_session;
ChunkPosSet old_set; ChunkPosSet old_set;
std::string name;
{ {
std::lock_guard lock(m_player_mutex); std::lock_guard lock(m_player_mutex);
auto it = m_players.find(uuid); auto it = m_players.find(uuid);
if (it != m_players.end()) { if (it != m_players.end()) {
Logger::info("Player {} Exit the Server", it->second.get_name()); name = it->second.get_name();
Logger::info("Player {} Exit the Server", name);
exit_session = it->second.get_session(); exit_session = it->second.get_session();
old_set = std::move(it->second.get_chunk_pos_set()); old_set = std::move(it->second.get_chunk_pos_set());
m_players.erase(it); m_players.erase(it);
} else { } else {
Logger::error("Player {} isn't in Server", uuid); Logger::error("Player {} isn't in Server", uuid);
return; return;
@@ -723,6 +729,9 @@ void ServerWorld::handle_player_exit(const std::string& uuid) {
s->send(make_packet(*rsp), 0); s->send(make_packet(*rsp), 0);
} }
} }
boardcast_message("Server", std::format("Player {} Exit Game", name),
Color::YELLOW, true);
} }
glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const { glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
@@ -910,7 +919,8 @@ void ServerWorld::send_server_stop() {
} }
void ServerWorld::boardcast_message(const std::string& name, void ServerWorld::boardcast_message(const std::string& name,
const std::string& message) { const std::string& message, Color color,
bool system_msg) {
std::vector<std::shared_ptr<Session>> m_session; std::vector<std::shared_ptr<Session>> m_session;
{ {
@@ -925,6 +935,8 @@ void ServerWorld::boardcast_message(const std::string& name,
msg->set_msg(message); msg->set_msg(message);
msg->set_name(name); msg->set_name(name);
msg->set_color(std::to_underlying(color));
msg->set_system_msg(system_msg);
for (auto& s : m_session) { for (auto& s : m_session) {
s->send(make_packet(*msg)); s->send(make_packet(*msg));

View File

@@ -3,6 +3,8 @@ import "common/vector3.proto";
message ChatMsg { message ChatMsg {
string name = 1; string name = 1;
string msg = 2; string msg = 2;
int32 color = 3;
bool system_msg = 4;
} }
message VoiceMsg { message VoiceMsg {

View File

@@ -12,12 +12,14 @@ void ChatBox::add_message(ChatMessage& message) {
m_messages.pop_front(); m_messages.pop_front();
} }
std::string str = std::format("<{}>{}", message.player, message.text); std::string str = message.system_msg
? std::format("{}", message.text)
: std::format("<{}>{}", message.player, message.text);
auto split_str = wrap_message(str); auto split_str = wrap_message(str);
for (auto it = split_str.begin(); it != split_str.end(); ++it) { for (auto it = split_str.begin(); it != split_str.end(); ++it) {
auto lable = std::make_unique<Label>(this); auto lable = std::make_unique<Label>(this);
lable->set_text(*it).set_scale(m_text_scale); lable->set_text(*it).set_scale(m_text_scale).set_color(message.color);
auto background = std::make_unique<Rect>(lable.get()); auto background = std::make_unique<Rect>(lable.get());
background->set_fill_height(true); background->set_fill_height(true);
background->set_anchor(Anchor::TOP_LEFT); background->set_anchor(Anchor::TOP_LEFT);

View File

@@ -51,7 +51,8 @@ void WorldUIManager::init() {
chat_box.set_text_scale(0.6f); chat_box.set_text_scale(0.6f);
chat_box.set_on_finish([this, &chat_box]() { chat_box.set_on_finish([this, &chat_box]() {
ChatMessage message{m_scene.client_world().get_player().get_name(), ChatMessage message{m_scene.client_world().get_player().get_name(),
std::move(chat_box.get_input_text()), 0}; std::move(chat_box.get_input_text()), Color::WHITE,
false, 0};
chat_box.clear_input(); chat_box.clear_input();
m_scene.client_world().send_chat_message(message); m_scene.client_world().send_chat_message(message);
}); });