mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(multiplayer): add rendering of other players as colored cubes
This commit is contained in:
8
assets/shaders/player_f_shader.glsl
Normal file
8
assets/shaders/player_f_shader.glsl
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 460
|
||||
|
||||
out vec4 color;
|
||||
in vec2 tc;
|
||||
|
||||
void main() {
|
||||
color = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
15
assets/shaders/player_v_shader.glsl
Normal file
15
assets/shaders/player_v_shader.glsl
Normal file
@@ -0,0 +1,15 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
|
||||
uniform mat4 mv_matrix;
|
||||
uniform mat4 proj_matrix;
|
||||
|
||||
out vec2 tc;
|
||||
|
||||
void main() {
|
||||
vec4 viewPos = mv_matrix * vec4(pos, 1.0);
|
||||
tc = texCoord;
|
||||
gl_Position = proj_matrix * viewPos;
|
||||
}
|
||||
@@ -10,6 +10,16 @@
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
namespace Cubed {
|
||||
|
||||
struct OtherPlayerInfo {
|
||||
std::string name;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
struct RenderPlayerData {
|
||||
std::string name;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
class ClientWorld {
|
||||
public:
|
||||
ClientWorld();
|
||||
@@ -34,6 +44,8 @@ public:
|
||||
void receive_block_change(const BlockChangeRsp& rsp);
|
||||
void receive_time(const UpdateTime& rsp);
|
||||
|
||||
void receive_other_player(const PlayerInfoRsp& rsp);
|
||||
|
||||
int rendering_distance() const;
|
||||
void rendering_distance(int rendering_distance);
|
||||
void start_client_thread(std::string_view uuid);
|
||||
@@ -42,7 +54,8 @@ public:
|
||||
void hot_reload();
|
||||
void request_chunk();
|
||||
std::vector<glm::vec4>& planes();
|
||||
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
||||
const std::vector<ChunkRenderSnapshot>& render_snapshots() const;
|
||||
const std::vector<RenderPlayerData>& render_player_data() const;
|
||||
glm::vec3 sunlight_dir() const;
|
||||
void receive_chunk(const ChunkDataRsp& data);
|
||||
template <typename Fn>
|
||||
@@ -58,7 +71,9 @@ private:
|
||||
tbb::concurrent_unordered_map<ChunkPos, ClientChunk, ChunkPos::Hash>;
|
||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||
using ChunkPosVector = std::vector<ChunkPos>;
|
||||
using OtherPlayerHashMap = std::unordered_map<std::string, OtherPlayerInfo>;
|
||||
ClientPlayer m_player;
|
||||
OtherPlayerHashMap m_other_players;
|
||||
ChunkHashMap m_chunks;
|
||||
std::vector<glm::vec4> m_planes;
|
||||
std::jthread m_client_thread;
|
||||
@@ -68,12 +83,17 @@ private:
|
||||
std::mutex m_delete_vao_mutex;
|
||||
std::mutex m_pending_upload_queue_mutex;
|
||||
std::mutex m_pending_chunk_data_queue_mutex;
|
||||
std::mutex m_other_players_mutex;
|
||||
|
||||
std::deque<ClientChunk> m_pending_upload_queue;
|
||||
std::deque<ChunkDataRsp> m_pending_chunk_data_queue;
|
||||
|
||||
std::vector<GLuint> m_pending_delete_vbo;
|
||||
std::vector<GLuint> m_pending_delete_vao;
|
||||
|
||||
std::deque<ChunkPos> m_dirty_queue;
|
||||
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
||||
std::vector<RenderPlayerData> m_render_player_data;
|
||||
tbb::concurrent_unordered_map<std::string, Timer> m_timers;
|
||||
std::atomic<bool> m_game_running{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
|
||||
@@ -13,6 +13,7 @@ enum class PacketEnum {
|
||||
LOGIN_RSP = 1002,
|
||||
PLAYER_INFO = 2001,
|
||||
PLAYER_POS = 2002,
|
||||
PLAYER_INFO_RSP = 2003,
|
||||
CHUNK_DATA_REQ = 3001,
|
||||
CHUNK_DATA_RSP = 3002,
|
||||
BLOCK_CHANGE_REQ = 3003,
|
||||
@@ -38,6 +39,8 @@ template <typename T> constexpr uint16_t get_packet_id() {
|
||||
return to_num(PLAYER_INFO);
|
||||
} else if constexpr (is_same_v<U, PlayerPos>) {
|
||||
return to_num(PLAYER_POS);
|
||||
} else if constexpr (is_same_v<U, PlayerInfoRsp>) {
|
||||
return to_num(PLAYER_INFO_RSP);
|
||||
} else if constexpr (is_same_v<U, ChunkDataReq>) {
|
||||
return to_num(CHUNK_DATA_REQ);
|
||||
} else if constexpr (is_same_v<U, ChunkDataRsp>) {
|
||||
|
||||
@@ -272,6 +272,55 @@ constexpr float CROSS_TANGENTS[2][6][3] = {
|
||||
{-0.7071f, 0.0f, 0.7071f}}};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Player
|
||||
|
||||
constexpr float VERTICES_PLAYER[6][6][3] = {
|
||||
// ===== front (z = +1) =====
|
||||
{{0.0f, 0.0f, 1.0f}, // bottom left
|
||||
{0.0f, 2.0f, 1.0f}, // top left
|
||||
{1.0f, 2.0f, 1.0f}, // top right
|
||||
{1.0f, 2.0f, 1.0f}, // top right
|
||||
{1.0f, 0.0f, 1.0f}, // bottom right
|
||||
{0.0f, 0.0f, 1.0f}}, // bottom left
|
||||
// ===== right (x = +1) =====
|
||||
{{1.0f, 0.0f, 1.0f}, // bottom front
|
||||
{1.0f, 0.0f, 0.0f}, // bottom back
|
||||
{1.0f, 2.0f, 0.0f}, // top back
|
||||
{1.0f, 2.0f, 0.0f}, // top back
|
||||
{1.0f, 2.0f, 1.0f}, // top front
|
||||
{1.0f, 0.0f, 1.0f}}, // bottom front
|
||||
// ===== back (z = -1) =====
|
||||
{{0.0f, 0.0f, 0.0f}, // bottom left
|
||||
{1.0f, 0.0f, 0.0f}, // bottom right
|
||||
{1.0f, 2.0f, 0.0f}, // top right
|
||||
{1.0f, 2.0f, 0.0f}, // top right
|
||||
{0.0f, 2.0f, 0.0f}, // top left
|
||||
{0.0f, 0.0f, 0.0f}}, // bottom left
|
||||
// ===== left (x = -1) =====
|
||||
{{0.0f, 0.0f, 0.0f}, // bottom back
|
||||
{0.0f, 0.0f, 1.0f}, // bottom front
|
||||
{0.0f, 2.0f, 1.0f}, // top front
|
||||
{0.0f, 2.0f, 1.0f}, // top front
|
||||
{0.0f, 2.0f, 0.0f}, // top back
|
||||
{0.0f, 0.0f, 0.0f}}, // bottom back
|
||||
// ===== top (y = +2) =====
|
||||
{{0.0f, 2.0f, 0.0f}, // back left
|
||||
{1.0f, 2.0f, 0.0f}, // back right
|
||||
{1.0f, 2.0f, 1.0f}, // front right
|
||||
{1.0f, 2.0f, 1.0f}, // front right
|
||||
{0.0f, 2.0f, 1.0f}, // front left
|
||||
{0.0f, 2.0f, 0.0f}}, // back left
|
||||
// ===== bottom (y = -1) =====
|
||||
{{0.0f, 0.0f, 1.0f}, // front left
|
||||
{1.0f, 0.0f, 1.0f}, // front right
|
||||
{1.0f, 0.0f, 0.0f}, // back right
|
||||
{1.0f, 0.0f, 0.0f}, // back right
|
||||
{0.0f, 0.0f, 0.0f}, // back left
|
||||
{0.0f, 0.0f, 1.0f}} // front left
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
// [-1, 1]
|
||||
constexpr float QUAD_VERTICES[] = {
|
||||
// postion // texcoorlds
|
||||
|
||||
@@ -122,7 +122,7 @@ private:
|
||||
GLuint m_outline_indices_vbo = 0;
|
||||
GLuint m_outline_vbo = 0;
|
||||
GLuint m_ui_vbo = 0;
|
||||
|
||||
GLuint m_player_vbo = 0;
|
||||
GLuint m_fbo = 0;
|
||||
GLuint m_screen_texture = 0;
|
||||
GLuint m_screen_depth_texture = 0;
|
||||
@@ -174,7 +174,7 @@ private:
|
||||
2 - outline vao
|
||||
3 - ui vao
|
||||
4 - text vao
|
||||
|
||||
5 - player vao
|
||||
*/
|
||||
std::vector<GLuint> m_vao;
|
||||
std::vector<Vertex2D> m_ui;
|
||||
@@ -189,6 +189,7 @@ private:
|
||||
void render_text();
|
||||
void render_ui();
|
||||
void render_world();
|
||||
void render_player();
|
||||
void render_underwater();
|
||||
void render_dev_panel();
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
@@ -400,6 +400,8 @@ void ServerWorld::update() {
|
||||
|
||||
void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,
|
||||
float z) {
|
||||
std::string name;
|
||||
{
|
||||
std::lock_guard lock(m_player_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
@@ -407,6 +409,31 @@ void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerWorld::handle_player_login(const std::string& name,
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -6,3 +6,9 @@ message PlayerPos {
|
||||
string uuid = 1;
|
||||
Vec3 pos = 2;
|
||||
}
|
||||
|
||||
message PlayerInfoRsp {
|
||||
string uuid = 1;
|
||||
string name = 2;
|
||||
Vec3 pos = 3;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user