feat(multiplayer): add rendering of other players as colored cubes

This commit is contained in:
2026-06-26 15:52:22 +08:00
parent 3c14a4ffe1
commit 48300b5fe2
12 changed files with 204 additions and 16 deletions

View File

@@ -190,13 +190,23 @@ void ClientWorld::receive_time(const UpdateTime& rsp) {
m_day_tick = rsp.day_tick();
}
void ClientWorld::receive_other_player(const PlayerInfoRsp& rsp) {
{
std::lock_guard lock(m_other_players_mutex);
m_other_players[rsp.uuid()].name = rsp.name();
m_other_players[rsp.uuid()].pos =
glm::vec3{rsp.pos().x(), rsp.pos().y(), rsp.pos().z()};
// Logger::info("Player {} pos Update", rsp.name());
}
}
void ClientWorld::init(std::string_view player_name,
std::shared_ptr<NetworkClient> client) {
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
m_player.init(player_name);
m_client = client;
// timer
register_timer("player_pos", 2, [this]() { report_player_pos(); });
register_timer("player_pos", 1, [this]() { report_player_pos(); });
LoginReq req;
req.set_name(m_player.get_name());
while (!client->is_connected()) {
@@ -450,6 +460,13 @@ void ClientWorld::update(float delta_time) {
}
}
}
m_render_player_data.clear();
{
std::lock_guard lock(m_other_players_mutex);
for (auto& [uuid, player] : m_other_players) {
m_render_player_data.emplace_back(player.name, player.pos);
}
}
}
glm::vec3 ClientWorld::sunlight_dir() const {
@@ -476,8 +493,11 @@ int ClientWorld::rendering_distance() const {
void ClientWorld::rendering_distance(int rendering_distance) {
m_rendering_distance = rendering_distance;
}
std::vector<ChunkRenderSnapshot>& ClientWorld::render_snapshots() {
const std::vector<ChunkRenderSnapshot>& ClientWorld::render_snapshots() const {
return m_render_snapshots;
};
const std::vector<RenderPlayerData>& ClientWorld::render_player_data() const {
return m_render_player_data;
}
std::vector<glm::vec4>& ClientWorld::planes() { return m_planes; }
} // namespace Cubed

View File

@@ -81,8 +81,8 @@ asio::awaitable<void> NetworkClient::read_loop() {
} break;
case to_num(PacketEnum::CHUNK_DATA_RSP): {
ChunkDataRsp rsp;
Logger::info("Client: Receive Chunk Data rsp, size {}mb",
body_data.size() / 1024.0f / 1024);
// Logger::info("Client: Receive Chunk Data rsp, size {}mb",
// body_data.size() / 1024.0f / 1024);
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
m_world.receive_chunk(rsp);
}
@@ -100,6 +100,12 @@ asio::awaitable<void> NetworkClient::read_loop() {
m_world.receive_time(rsp);
}
}
case to_num(PacketEnum::PLAYER_INFO_RSP): {
PlayerInfoRsp rsp;
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
m_world.receive_other_player(rsp);
}
} break;
}
}
} catch (const asio::system_error& e) {

View File

@@ -400,13 +400,40 @@ void ServerWorld::update() {
void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,
float z) {
std::lock_guard lock(m_player_mutex);
auto it = m_players.find(uuid);
if (it == m_players.end()) {
Logger::warn("Player {} is not in this Server", uuid);
return;
std::string name;
{
std::lock_guard lock(m_player_mutex);
auto it = m_players.find(uuid);
if (it == m_players.end()) {
Logger::warn("Player {} is not in this Server", uuid);
return;
}
it->second.update_pos(x, y, z);
name = it->second.get_name();
}
// update other player pos;
std::vector<std::shared_ptr<Session>> other;
{
std::shared_lock lock(m_player_mutex);
for (auto& [o_uuid, player] : m_players) {
if (o_uuid == uuid) {
continue;
}
other.emplace_back(player.get_session());
}
}
for (auto& session : other) {
PlayerInfoRsp rsp;
rsp.set_uuid(uuid);
rsp.set_name(name);
auto* pos = rsp.mutable_pos();
pos->set_x(x);
pos->set_y(y);
pos->set_z(z);
session->send(make_packet(rsp));
}
it->second.update_pos(x, y, z);
}
void ServerWorld::handle_player_login(const std::string& name,

View File

@@ -77,7 +77,7 @@ asio::awaitable<void> Session::read_loop() {
}
if (cmd_id == to_num(PacketEnum::CHUNK_DATA_REQ)) {
ChunkDataReq req;
Logger::info("Session: Receive Chunk Data req");
// Logger::info("Session: Receive Chunk Data req");
if (req.ParseFromArray(body_data.data(), body_data.size())) {
m_server_world.handle_chunk_req(
req.uuid(), ChunkPos(req.pos().x(), req.pos().z()));

View File

@@ -5,4 +5,10 @@ import "common/vector3.proto";
message PlayerPos {
string uuid = 1;
Vec3 pos = 2;
}
message PlayerInfoRsp {
string uuid = 1;
string name = 2;
Vec3 pos = 3;
}

View File

@@ -34,6 +34,7 @@ Renderer::~Renderer() {
glDeleteBuffers(1, &m_sky_vbo);
glDeleteBuffers(1, &m_ui_vbo);
glDeleteBuffers(1, &m_text_vbo);
glDeleteBuffers(1, &m_player_vbo);
glBindVertexArray(0);
glDeleteVertexArrays(NUM_VAO, m_vao.data());
glDeleteFramebuffers(1, &m_fbo);
@@ -88,7 +89,9 @@ void Renderer::init() {
"shaders/billboard_f_shader.glsl"};
Shader water_shader{"water", "shaders/water_v_shader.glsl",
"shaders/water_f_shader.glsl"};
Shader player_shader{"player", "shaders/player_v_shader.glsl",
"shaders/player_f_shader.glsl"};
m_shaders.insert({player_shader.hash(), std::move(player_shader)});
m_shaders.insert({world_shader.hash(), std::move(world_shader)});
m_shaders.insert({outline_shader.hash(), std::move(outline_shader)});
m_shaders.insert({sky_shdaer.hash(), std::move(sky_shdaer)});
@@ -102,6 +105,7 @@ void Renderer::init() {
m_shaders.insert({depth_shader.hash(), std::move(depth_shader)});
m_shaders.insert({billboard.hash(), std::move(billboard)});
m_shaders.insert({water_shader.hash(), std::move(water_shader)});
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
@@ -167,6 +171,15 @@ void Renderer::init() {
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindVertexArray(m_vao[5]);
glGenBuffers(1, &m_player_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_player_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES_PLAYER), VERTICES_PLAYER,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
init_quad();
init_text();
hot_reload();
@@ -217,7 +230,7 @@ void Renderer::render() {
render_sky();
render_world();
render_outline();
render_player();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_FRAMEBUFFER_SRGB);
glDisable(GL_DEPTH_TEST);
@@ -927,6 +940,26 @@ void Renderer::render_world() {
DebugCollector::get().report(
"rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum));
}
void Renderer::render_player() {
auto& shader = get_shader("player");
shader.use();
m_v_mat = m_camera.get_camera_lookat();
auto& players = m_world.render_player_data();
for (auto& player : players) {
m_m_mat = glm::translate(glm::mat4(1.0f),
player.pos + glm::vec3(-0.5f, 0.0f, -0.5f));
m_mv_mat = m_v_mat * m_m_mat;
shader.set_loc("mv_matrix", m_mv_mat);
shader.set_loc("proj_matrix", m_p_mat);
glBindVertexArray(m_vao[5]);
glEnable(GL_DEPTH_TEST);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
#pragma endregion
void Renderer::render_dev_panel() {
glDisable(GL_DEPTH_TEST);