mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(gameplay): integrate network client and thread-safe player pos
This commit is contained in:
@@ -8,18 +8,20 @@
|
|||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <shared_mutex>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
enum class Gait { WALK = 0, RUN };
|
enum class Gait { WALK = 0, RUN };
|
||||||
class ClientWorld;
|
class ClientWorld;
|
||||||
class ClientPlayer {
|
class ClientPlayer {
|
||||||
public:
|
public:
|
||||||
ClientPlayer(ClientWorld& world, const std::string& name);
|
ClientPlayer(ClientWorld& world, std::string_view name);
|
||||||
~ClientPlayer();
|
~ClientPlayer();
|
||||||
AABB get_aabb() const;
|
AABB get_aabb() const;
|
||||||
const glm::vec3& get_front() const;
|
const glm::vec3& get_front() const;
|
||||||
const Gait& get_gait() const;
|
const Gait& get_gait() const;
|
||||||
const std::optional<LookBlock>& get_look_block_pos() const;
|
const std::optional<LookBlock>& get_look_block_pos() const;
|
||||||
const glm::vec3& get_player_pos() const;
|
// thread safe
|
||||||
|
glm::vec3 get_player_pos() const;
|
||||||
const MoveState& get_move_state() const;
|
const MoveState& get_move_state() const;
|
||||||
|
|
||||||
void change_mode(GameMode mode);
|
void change_mode(GameMode mode);
|
||||||
@@ -48,6 +50,7 @@ public:
|
|||||||
|
|
||||||
void set_uuid(std::string_view uuid);
|
void set_uuid(std::string_view uuid);
|
||||||
const std::string& get_uuid() const;
|
const std::string& get_uuid() const;
|
||||||
|
const std::string& get_name() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using enum GameMode;
|
using enum GameMode;
|
||||||
@@ -94,6 +97,9 @@ private:
|
|||||||
std::string m_name{};
|
std::string m_name{};
|
||||||
std::string m_uuid;
|
std::string m_uuid;
|
||||||
ClientWorld& m_world;
|
ClientWorld& m_world;
|
||||||
|
|
||||||
|
std::shared_mutex m_player_pos_mutex;
|
||||||
|
|
||||||
bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
|
bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
|
||||||
glm::ivec3& block_pos, glm::vec3& normal,
|
glm::ivec3& block_pos, glm::vec3& normal,
|
||||||
float distance = 4.0f);
|
float distance = 4.0f);
|
||||||
@@ -101,8 +107,8 @@ private:
|
|||||||
void update_direction();
|
void update_direction();
|
||||||
void update_lookup_block();
|
void update_lookup_block();
|
||||||
void update_move(float delta_time);
|
void update_move(float delta_time);
|
||||||
void update_x_move();
|
void update_x_move(glm::vec3& player_pos);
|
||||||
void update_y_move();
|
void update_y_move(glm::vec3& player_pos);
|
||||||
void update_z_move();
|
void update_z_move(glm::vec3& player_pos);
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
#include "Cubed/gameplay/client_chunk.hpp"
|
#include "Cubed/gameplay/client_chunk.hpp"
|
||||||
#include "Cubed/gameplay/client_player.hpp"
|
#include "Cubed/gameplay/client_player.hpp"
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
|
#include "Cubed/gameplay/network_client.hpp"
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <tbb/concurrent_unordered_map.h>
|
#include <tbb/concurrent_unordered_map.h>
|
||||||
@@ -11,7 +13,8 @@ namespace Cubed {
|
|||||||
|
|
||||||
class ClientWorld {
|
class ClientWorld {
|
||||||
public:
|
public:
|
||||||
ClientWorld();
|
ClientWorld(std::string_view player_name,
|
||||||
|
std::shared_ptr<NetworkClient> client);
|
||||||
~ClientWorld();
|
~ClientWorld();
|
||||||
void init();
|
void init();
|
||||||
void update(float delta_time);
|
void update(float delta_time);
|
||||||
@@ -32,16 +35,23 @@ public:
|
|||||||
|
|
||||||
int rendering_distance() const;
|
int rendering_distance() const;
|
||||||
void rendering_distance(int rendering_distance);
|
void rendering_distance(int rendering_distance);
|
||||||
void start_client_thread();
|
void start_client_thread(std::string_view uuid);
|
||||||
void stop_client_thread();
|
void stop_client_thread();
|
||||||
|
|
||||||
std::vector<glm::vec4>& planes();
|
std::vector<glm::vec4>& planes();
|
||||||
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
std::vector<ChunkRenderSnapshot>& render_snapshots();
|
||||||
glm::vec3 sunlight_dir() const;
|
glm::vec3 sunlight_dir() const;
|
||||||
|
void receive_chunk(const ChunkDataRsp& data);
|
||||||
|
template <typename Fn>
|
||||||
|
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||||
|
m_timers.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(std::string(id)),
|
||||||
|
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using ChunkHashMap =
|
using ChunkHashMap =
|
||||||
tbb::concurrent_unordered_map<ChunkPos, ClientChunk, ChunkPos::Hash>;
|
tbb::concurrent_unordered_map<ChunkPos, ClientChunk, ChunkPos::Hash>;
|
||||||
|
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||||
ClientPlayer m_player;
|
ClientPlayer m_player;
|
||||||
ChunkHashMap m_chunks;
|
ChunkHashMap m_chunks;
|
||||||
std::vector<glm::vec4> m_planes;
|
std::vector<glm::vec4> m_planes;
|
||||||
@@ -50,10 +60,23 @@ private:
|
|||||||
mutable std::shared_mutex m_chunks_mutex;
|
mutable std::shared_mutex m_chunks_mutex;
|
||||||
std::mutex m_delete_vbo_mutex;
|
std::mutex m_delete_vbo_mutex;
|
||||||
std::mutex m_delete_vao_mutex;
|
std::mutex m_delete_vao_mutex;
|
||||||
|
std::mutex m_pending_queue_mutex;
|
||||||
|
std::deque<ClientChunk> m_pending_queue;
|
||||||
|
|
||||||
std::vector<GLuint> m_pending_delete_vbo;
|
std::vector<GLuint> m_pending_delete_vbo;
|
||||||
std::vector<GLuint> m_pending_delete_vao;
|
std::vector<GLuint> m_pending_delete_vao;
|
||||||
std::deque<ChunkPos> m_dirty_queue;
|
std::deque<ChunkPos> m_dirty_queue;
|
||||||
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
std::vector<ChunkRenderSnapshot> m_render_snapshots;
|
||||||
|
tbb::concurrent_unordered_map<std::string, Timer> m_timers;
|
||||||
|
std::atomic<bool> m_game_running{false};
|
||||||
|
std::atomic<int> m_rendering_distance{24};
|
||||||
|
std::shared_ptr<NetworkClient> m_client;
|
||||||
|
void client_run(std::stop_token token);
|
||||||
|
|
||||||
|
void set_player_pos();
|
||||||
|
|
||||||
|
void report_player_pos();
|
||||||
|
|
||||||
|
void request_chunk();
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -1,10 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Prevent unsigned underflow issues in subtraction
|
// Prevent unsigned underflow issues in subtraction
|
||||||
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
namespace Cubed {
|
||||||
using TickType = long long;
|
using TickType = long long;
|
||||||
|
|
||||||
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
constexpr int DEFAULT_PER_TICK_TIME = 50;
|
||||||
|
|
||||||
constexpr TickType DAY_TIME = 24000;
|
constexpr TickType DAY_TIME = 24000;
|
||||||
|
|
||||||
constexpr TickType PER_HOUR = 1000;
|
constexpr TickType PER_HOUR = 1000;
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
public:
|
||||||
|
template <typename Fn>
|
||||||
|
Timer(TickType threshold, Fn&& f)
|
||||||
|
: m_fn(std::forward<Fn>(f)), m_threshold(threshold) {
|
||||||
|
ASSERT_MSG(threshold > 0, "Threshold Must Rreater Than 0");
|
||||||
|
}
|
||||||
|
bool update() {
|
||||||
|
if (++m_current >= m_threshold) {
|
||||||
|
m_current = 0;
|
||||||
|
m_fn();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void reset() { m_current = 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> m_fn;
|
||||||
|
TickType m_threshold;
|
||||||
|
TickType m_current = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
using asio::ip::tcp;
|
using asio::ip::tcp;
|
||||||
|
class ClientWorld;
|
||||||
class NetworkClient : std::enable_shared_from_this<NetworkClient> {
|
class NetworkClient : std::enable_shared_from_this<NetworkClient> {
|
||||||
public:
|
public:
|
||||||
NetworkClient();
|
NetworkClient(ClientWorld& world);
|
||||||
~NetworkClient();
|
~NetworkClient();
|
||||||
void close();
|
void close();
|
||||||
asio::awaitable<void> connect(std::string ip, int port);
|
asio::awaitable<void> connect(std::string ip, int port);
|
||||||
@@ -29,7 +30,7 @@ private:
|
|||||||
std::atomic<bool> m_closed{false};
|
std::atomic<bool> m_closed{false};
|
||||||
|
|
||||||
// ClientWorld is managed by App
|
// ClientWorld is managed by App
|
||||||
// ClientWorld& m_world;
|
ClientWorld& m_world;
|
||||||
|
|
||||||
void do_write();
|
void do_write();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -516,6 +516,7 @@ void ClientChunk::receive_chunk(const ChunkDataRsp& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gen_vertex_data(neighbor);
|
gen_vertex_data(neighbor);
|
||||||
|
mark_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
#include "Cubed/gameplay/client_world.hpp"
|
#include "Cubed/gameplay/client_world.hpp"
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
ClientPlayer::ClientPlayer(ClientWorld& world, const std::string& name)
|
ClientPlayer::ClientPlayer(ClientWorld& world, std::string_view name)
|
||||||
: m_world(world) {}
|
: m_name(name), m_world(world) {}
|
||||||
ClientPlayer::~ClientPlayer() {}
|
ClientPlayer::~ClientPlayer() {}
|
||||||
|
|
||||||
AABB ClientPlayer::get_aabb() const {
|
AABB ClientPlayer::get_aabb() const {
|
||||||
@@ -28,7 +28,11 @@ const Gait& ClientPlayer::get_gait() const { return m_gait; }
|
|||||||
const std::optional<LookBlock>& ClientPlayer::get_look_block_pos() const {
|
const std::optional<LookBlock>& ClientPlayer::get_look_block_pos() const {
|
||||||
return m_look_block;
|
return m_look_block;
|
||||||
}
|
}
|
||||||
const glm::vec3& ClientPlayer::get_player_pos() const { return m_player_pos; }
|
glm::vec3 ClientPlayer::get_player_pos() const {
|
||||||
|
|
||||||
|
std::shared_lock lock(m_player_pos_mutex);
|
||||||
|
return m_player_pos;
|
||||||
|
}
|
||||||
|
|
||||||
const MoveState& ClientPlayer::get_move_state() const { return m_move_state; }
|
const MoveState& ClientPlayer::get_move_state() const { return m_move_state; }
|
||||||
|
|
||||||
@@ -305,6 +309,14 @@ void ClientPlayer::update_move(float delta_time) {
|
|||||||
if (delta_time > 1.0f) {
|
if (delta_time > 1.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// ensure the thread safe
|
||||||
|
glm::vec3 player_pos;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_lock lock(m_player_pos_mutex);
|
||||||
|
player_pos = m_player_pos;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_game_mode != SPECTATOR) {
|
if (m_game_mode != SPECTATOR) {
|
||||||
if (m_gait == Gait::RUN) {
|
if (m_gait == Gait::RUN) {
|
||||||
m_max_speed = m_max_run_speed;
|
m_max_speed = m_max_run_speed;
|
||||||
@@ -366,19 +378,24 @@ void ClientPlayer::update_move(float delta_time) {
|
|||||||
|
|
||||||
move_distance.y = m_y_speed * delta_time;
|
move_distance.y = m_y_speed * delta_time;
|
||||||
// y
|
// y
|
||||||
update_y_move();
|
update_y_move(player_pos);
|
||||||
// x
|
// x
|
||||||
update_x_move();
|
update_x_move(player_pos);
|
||||||
|
|
||||||
update_z_move();
|
update_z_move(player_pos);
|
||||||
|
|
||||||
if (m_player_pos.y < -15.0f) {
|
if (player_pos.y < -15.0f) {
|
||||||
Logger::warn("y is tow low");
|
Logger::warn("y is tow low");
|
||||||
m_player_pos += glm::vec3(1.0f, 100.0f, 1.0f);
|
player_pos += glm::vec3(1.0f, 100.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_player_pos_mutex);
|
||||||
|
m_player_pos = player_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPlayer::update_x_move() {
|
void ClientPlayer::update_x_move(glm::vec3& m_player_pos) {
|
||||||
m_player_pos.x += move_distance.x;
|
m_player_pos.x += move_distance.x;
|
||||||
if (m_game_mode == SPECTATOR) {
|
if (m_game_mode == SPECTATOR) {
|
||||||
return;
|
return;
|
||||||
@@ -412,7 +429,7 @@ void ClientPlayer::update_x_move() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPlayer::update_y_move() {
|
void ClientPlayer::update_y_move(glm::vec3& m_player_pos) {
|
||||||
m_player_pos.y += move_distance.y;
|
m_player_pos.y += move_distance.y;
|
||||||
if (m_game_mode == SPECTATOR) {
|
if (m_game_mode == SPECTATOR) {
|
||||||
return;
|
return;
|
||||||
@@ -450,7 +467,7 @@ void ClientPlayer::update_y_move() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientPlayer::update_z_move() {
|
void ClientPlayer::update_z_move(glm::vec3& m_player_pos) {
|
||||||
m_player_pos.z += move_distance.z;
|
m_player_pos.z += move_distance.z;
|
||||||
if (m_game_mode == SPECTATOR) {
|
if (m_game_mode == SPECTATOR) {
|
||||||
return;
|
return;
|
||||||
@@ -522,4 +539,9 @@ unsigned ClientPlayer::place_block() const { return m_place_block; };
|
|||||||
Gait& ClientPlayer::gait() { return m_gait; }
|
Gait& ClientPlayer::gait() { return m_gait; }
|
||||||
GameMode& ClientPlayer::game_mode() { return m_game_mode; }
|
GameMode& ClientPlayer::game_mode() { return m_game_mode; }
|
||||||
const ClientWorld& ClientPlayer::get_world() const { return m_world; }
|
const ClientWorld& ClientPlayer::get_world() const { return m_world; }
|
||||||
|
|
||||||
|
void ClientPlayer::set_uuid(std::string_view uuid) { m_uuid = uuid; }
|
||||||
|
const std::string& ClientPlayer::get_uuid() const { return m_uuid; }
|
||||||
|
const std::string& ClientPlayer::get_name() const { return m_name; }
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
#include "Cubed/gameplay/client_world.hpp"
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
|
#include "Cubed/gameplay/packet.hpp"
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct ChunkRenderData {
|
||||||
|
std::array<const std::vector<BlockType>*, 4> neighbor_block;
|
||||||
|
ClientChunk* chunk;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ClientWorld::ClientWorld(std::string_view player_name,
|
||||||
|
std::shared_ptr<NetworkClient> client)
|
||||||
|
: m_player(*this, player_name), m_client(client) {}
|
||||||
|
|
||||||
|
ClientWorld::~ClientWorld() {
|
||||||
|
stop_client_thread();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_chunks_mutex);
|
||||||
|
m_chunks.clear();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_delete_vbo_mutex);
|
||||||
|
for (auto x : m_pending_delete_vbo) {
|
||||||
|
glDeleteBuffers(1, &x);
|
||||||
|
}
|
||||||
|
m_pending_delete_vbo.clear();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_delete_vao_mutex);
|
||||||
|
for (auto x : m_pending_delete_vao) {
|
||||||
|
glDeleteVertexArrays(1, &x);
|
||||||
|
}
|
||||||
|
m_pending_delete_vao.clear();
|
||||||
|
}
|
||||||
|
m_timers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::optional<LookBlock>&
|
||||||
|
ClientWorld::get_look_block_pos(const std::string& name) const {
|
||||||
|
|
||||||
|
return m_player.get_look_block_pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientPlayer& ClientWorld::get_player() { return m_player; }
|
||||||
|
|
||||||
|
void ClientWorld::init() {
|
||||||
|
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
|
||||||
|
|
||||||
|
// timer
|
||||||
|
register_timer("player_pos", 2, [this]() { report_player_pos(); });
|
||||||
|
|
||||||
|
LoginReq req;
|
||||||
|
req.set_name(m_player.get_name());
|
||||||
|
// request login
|
||||||
|
m_client->send(make_packet(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::start_client_thread(std::string_view uuid) {
|
||||||
|
if (m_game_running) {
|
||||||
|
Logger::error("Game Already Running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// response
|
||||||
|
m_player.set_uuid(uuid);
|
||||||
|
m_client_thread = std::jthread([this](std::stop_token token) {
|
||||||
|
m_game_running = true;
|
||||||
|
client_run(token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::stop_client_thread() {
|
||||||
|
m_client_thread.request_stop();
|
||||||
|
if (m_client_thread.joinable()) {
|
||||||
|
m_client_thread.join();
|
||||||
|
}
|
||||||
|
m_game_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::client_run(std::stop_token stoken) {
|
||||||
|
Logger::info("Client Thread Started");
|
||||||
|
while (!stoken.stop_requested()) {
|
||||||
|
for (auto& x : m_timers) {
|
||||||
|
x.second.update();
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(milliseconds(DEFAULT_PER_TICK_TIME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::report_player_pos() {
|
||||||
|
if (!m_client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlayerPos pos;
|
||||||
|
pos.set_uuid(m_player.get_uuid());
|
||||||
|
glm::vec3 player_pos = m_player.get_player_pos();
|
||||||
|
auto* v3 = pos.mutable_pos();
|
||||||
|
v3->set_x(player_pos.x);
|
||||||
|
v3->set_y(player_pos.y);
|
||||||
|
v3->set_z(player_pos.z);
|
||||||
|
m_client->send(make_packet(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::request_chunk() {
|
||||||
|
ChunkPosSet required_chunks;
|
||||||
|
|
||||||
|
glm::vec3 player_pos = m_player.get_player_pos();
|
||||||
|
|
||||||
|
int x = std::floor(player_pos.x);
|
||||||
|
int z = std::floor(player_pos.z);
|
||||||
|
auto [chunk_x, chunk_z] = get_chunk_pos(x, z);
|
||||||
|
int radius = m_rendering_distance;
|
||||||
|
int r2 = radius * radius;
|
||||||
|
required_chunks.reserve(radius * radius);
|
||||||
|
|
||||||
|
for (int dx = -radius; dx <= radius; ++dx) {
|
||||||
|
for (int dz = -radius; dz <= radius; ++dz) {
|
||||||
|
if (dx * dx + dz * dz <= r2) {
|
||||||
|
required_chunks.emplace(chunk_x + dx, chunk_z + dz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkPosSet need_send_pos;
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_chunks_mutex);
|
||||||
|
for (auto it = m_chunks.begin(); it != m_chunks.end();) {
|
||||||
|
if (required_chunks.find(it->first) == required_chunks.end()) {
|
||||||
|
it = m_chunks.unsafe_erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto pos : required_chunks) {
|
||||||
|
auto it = m_chunks.find(pos);
|
||||||
|
if (it == m_chunks.end()) {
|
||||||
|
need_send_pos.emplace(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (need_send_pos.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto uuid = m_player.get_uuid();
|
||||||
|
ChunkDataReq req;
|
||||||
|
for (const auto& pos : need_send_pos) {
|
||||||
|
req.set_uuid(uuid);
|
||||||
|
auto* p = req.mutable_pos();
|
||||||
|
p->set_x(pos.x);
|
||||||
|
p->set_z(pos.z);
|
||||||
|
m_client->send(make_packet(req));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::receive_chunk(const ChunkDataRsp& data) {
|
||||||
|
ClientChunk chunk{*this};
|
||||||
|
chunk.receive_chunk(data);
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_pending_queue_mutex);
|
||||||
|
m_pending_queue.emplace_back(std::move(chunk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientWorld::update(float delta_time) {
|
||||||
|
m_player.update(delta_time);
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_delete_vbo_mutex);
|
||||||
|
for (auto x : m_pending_delete_vbo) {
|
||||||
|
glDeleteBuffers(1, &x);
|
||||||
|
}
|
||||||
|
m_pending_delete_vbo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_delete_vao_mutex);
|
||||||
|
for (auto x : m_pending_delete_vao) {
|
||||||
|
glDeleteVertexArrays(1, &x);
|
||||||
|
}
|
||||||
|
m_pending_delete_vao.clear();
|
||||||
|
}
|
||||||
|
std::vector<ClientChunk> new_chunks;
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_pending_queue_mutex);
|
||||||
|
for (auto& c : m_pending_queue) {
|
||||||
|
new_chunks.emplace_back(std::move(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& c : new_chunks) {
|
||||||
|
c.upload_to_gpu();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_chunks_mutex);
|
||||||
|
for (auto& c : new_chunks) {
|
||||||
|
m_chunks.emplace(c.get_chunk_pos(), std::move(c));
|
||||||
|
}
|
||||||
|
m_render_snapshots.clear();
|
||||||
|
for (auto& [pos, chunk] : m_chunks) {
|
||||||
|
if (chunk.is_dirty()) {
|
||||||
|
// the curial fator influence
|
||||||
|
OptionalBlockVectorArray neighbor_block;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto it = m_chunks.find(pos + CHUNK_DIR[i]);
|
||||||
|
if (it != m_chunks.end()) {
|
||||||
|
neighbor_block[i] = (it->second.get_chunk_blocks());
|
||||||
|
} else {
|
||||||
|
neighbor_block[i] = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunk.gen_vertex_data(neighbor_block);
|
||||||
|
chunk.upload_to_gpu();
|
||||||
|
}
|
||||||
|
if (!chunk.is_dirty()) {
|
||||||
|
if (chunk.is_need_upload()) {
|
||||||
|
chunk.upload_to_gpu();
|
||||||
|
}
|
||||||
|
m_render_snapshots.push_back(
|
||||||
|
{chunk.get_normal_vao(), chunk.get_normal_vertices_sum(),
|
||||||
|
chunk.get_cross_vao(), chunk.get_cross_vertices_sum(),
|
||||||
|
chunk.get_normal_discard_vao(),
|
||||||
|
chunk.get_normal_discard_vertices_sum(),
|
||||||
|
chunk.get_normal_blend_vao(),
|
||||||
|
chunk.get_normal_blend_vertices_sum(),
|
||||||
|
chunk.get_water_vao(), chunk.get_water_vertices_sum(),
|
||||||
|
glm::vec3(static_cast<float>(pos.x * CHUNK_SIZE) +
|
||||||
|
static_cast<float>(CHUNK_SIZE / 2),
|
||||||
|
static_cast<float>(WORLD_SIZE_Y / 2),
|
||||||
|
static_cast<float>(pos.z * CHUNK_SIZE) +
|
||||||
|
static_cast<float>(CHUNK_SIZE / 2)),
|
||||||
|
glm::vec3(static_cast<float>(CHUNK_SIZE / 2),
|
||||||
|
static_cast<float>(WORLD_SIZE_Y / 2),
|
||||||
|
static_cast<float>(CHUNK_SIZE / 2))});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "Cubed/gameplay/network_client.hpp"
|
#include "Cubed/gameplay/network_client.hpp"
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/client_world.hpp"
|
||||||
#include "Cubed/tools/log.hpp"
|
#include "Cubed/tools/log.hpp"
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
NetworkClient::NetworkClient() : m_socket(m_io) {}
|
NetworkClient::NetworkClient(ClientWorld& world)
|
||||||
|
: m_socket(m_io), m_world(world) {}
|
||||||
|
|
||||||
NetworkClient::~NetworkClient() { close(); }
|
NetworkClient::~NetworkClient() { close(); }
|
||||||
|
|
||||||
@@ -58,6 +59,20 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
|||||||
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
||||||
switch (cmd_id) {
|
switch (cmd_id) {
|
||||||
case to_num(PacketEnum::LOGIN_RSP): {
|
case to_num(PacketEnum::LOGIN_RSP): {
|
||||||
|
LoginRsp rsp;
|
||||||
|
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
|
||||||
|
if (rsp.success()) {
|
||||||
|
m_world.start_client_thread(rsp.uuid());
|
||||||
|
} else {
|
||||||
|
Logger::error("Connected Server Fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case to_num(PacketEnum::CHUNK_DATA_RSP): {
|
||||||
|
ChunkDataRsp rsp;
|
||||||
|
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
|
||||||
|
m_world.receive_chunk(rsp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ ServerWorld::~ServerWorld() {
|
|||||||
stop_server_thread();
|
stop_server_thread();
|
||||||
wait_all_chunk_tasks();
|
wait_all_chunk_tasks();
|
||||||
stop_thread_pool();
|
stop_thread_pool();
|
||||||
|
{
|
||||||
m_chunks.clear();
|
std::lock_guard lock(m_chunks_mutex);
|
||||||
|
m_chunks.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerWorld::wait_all_chunk_tasks() {
|
void ServerWorld::wait_all_chunk_tasks() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
message ChunkPos {
|
message ChunkPosNet {
|
||||||
int32 x = 1;
|
int32 x = 1;
|
||||||
int32 z = 2;
|
int32 z = 2;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
import "common/chunk_pos.proto";
|
|
||||||
import "common/error.proto";
|
import "common/error.proto";
|
||||||
import "common/player_info.proto";
|
import "common/player_info.proto";
|
||||||
import "common/vector3.proto";
|
import "common/vector3.proto";
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import "common/chunk_pos.proto";
|
|||||||
|
|
||||||
message ChunkDataReq {
|
message ChunkDataReq {
|
||||||
string uuid = 1;
|
string uuid = 1;
|
||||||
ChunkPos pos = 2;
|
ChunkPosNet pos = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChunkDataRsp {
|
message ChunkDataRsp {
|
||||||
ChunkPos pos = 1;
|
ChunkPosNet pos = 1;
|
||||||
uint32 chunk_seed = 2;
|
uint32 chunk_seed = 2;
|
||||||
int32 biome_type = 3;
|
int32 biome_type = 3;
|
||||||
repeated uint32 chunk_blocks = 4 [packed=true];
|
repeated uint32 chunk_blocks = 4 [packed=true];
|
||||||
|
|||||||
Reference in New Issue
Block a user