feat(gameplay): add time sync and network improvements

This commit is contained in:
2026-06-25 20:13:51 +08:00
parent d7d47e9e7f
commit 47552a1887
12 changed files with 123 additions and 10 deletions

View File

@@ -13,7 +13,11 @@ namespace Cubed {
App::App() {}
App::~App() {}
App::~App() {
if (m_client) {
m_client->stop();
}
}
void App::cursor_position_callback(GLFWwindow* window, double xpos,
double ypos) {
ImGuiIO& io = ImGui::GetIO();

View File

@@ -185,6 +185,11 @@ void ClientWorld::receive_block_change(const BlockChangeRsp& rsp) {
set_block(pos, rsp.block());
}
void ClientWorld::receive_time(const UpdateTime& rsp) {
m_game_ticks = rsp.game_tick();
m_day_tick = rsp.day_tick();
}
void ClientWorld::init(std::string_view player_name,
std::shared_ptr<NetworkClient> client) {
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
@@ -195,7 +200,11 @@ void ClientWorld::init(std::string_view player_name,
LoginReq req;
req.set_name(m_player.get_name());
while (!client->is_connected()) {
std::this_thread::sleep_for(milliseconds(200));
}
// request login
Logger::info("Send Login Request");
m_client->send(make_packet(req));
}
@@ -384,4 +393,32 @@ void ClientWorld::update(float delta_time) {
}
}
glm::vec3 ClientWorld::sunlight_dir() const {
float altitude = sin((m_day_tick - 6 * PER_HOUR) /
static_cast<float>(DAY_TIME / 2) * std::numbers::pi) *
90.0f;
float t = static_cast<float>(m_day_tick) / DAY_TIME;
float azimuth = 90.0f - 360.0f * (t - 0.25f);
float alt = glm::radians(altitude);
float az = glm::radians(azimuth);
glm::vec3 dir;
dir.x = cos(alt) * sin(az);
dir.y = sin(alt);
dir.z = cos(alt) * cos(az);
return glm::normalize(-dir);
}
int ClientWorld::rendering_distance() const {
return m_rendering_distance.load();
}
void ClientWorld::rendering_distance(int rendering_distance) {
m_rendering_distance = rendering_distance;
}
std::vector<ChunkRenderSnapshot>& ClientWorld::render_snapshots() {
return m_render_snapshots;
};
std::vector<glm::vec4>& ClientWorld::planes() { return m_planes; }
} // namespace Cubed

View File

@@ -16,16 +16,24 @@ void NetworkClient::start(std::string ip, int port) {
asio::co_spawn(self->m_strand, self->connect(ip, port), asio::detached);
self->m_io.run();
});
Logger::info("NetworkClient Started");
}
bool NetworkClient::is_connected() const { return m_connected.load(); }
asio::awaitable<void> NetworkClient::connect(std::string ip, int port) {
Logger::info("Connect Begin");
try {
auto ex = co_await asio::this_coro::executor;
tcp::resolver resolver(ex);
auto eps = co_await resolver.async_resolve(ip, std::to_string(port),
asio::use_awaitable);
Logger::info("Resolve Success");
co_await async_connect(m_socket, eps, asio::use_awaitable);
Logger::info("Connect Success, Server ip {} port {}", ip, port);
asio::co_spawn(m_strand, read_loop(), asio::detached);
Logger::info("NetworkClient Read Loop Started");
m_connected = true;
co_return;
} catch (const std::exception& e) {
@@ -56,6 +64,7 @@ asio::awaitable<void> NetworkClient::read_loop() {
co_await asio::async_read(m_socket, asio::buffer(body_data),
asio::use_awaitable);
}
Logger::info("Client: Receive cmd {}", cmd_id);
constexpr auto& to_num = std::to_underlying<PacketEnum>;
switch (cmd_id) {
case to_num(PacketEnum::LOGIN_RSP): {
@@ -67,19 +76,19 @@ asio::awaitable<void> NetworkClient::read_loop() {
Logger::error("Connected Server Fail");
}
}
}
} break;
case to_num(PacketEnum::CHUNK_DATA_RSP): {
ChunkDataRsp rsp;
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
m_world.receive_chunk(rsp);
}
}
} break;
case to_num(PacketEnum::BLOCK_CHANGE_RSP): {
BlockChangeRsp rsp;
if (rsp.ParseFromArray(body_data.data(), body_data.size())) {
m_world.receive_block_change(rsp);
}
}
} break;
}
}
} catch (const asio::system_error& e) {
@@ -104,6 +113,9 @@ asio::awaitable<void> NetworkClient::read_loop() {
}
void NetworkClient::send(std::shared_ptr<std::vector<uint8_t>> packet) {
if (m_closed.load()) {
return;
}
asio::post(m_strand, [self = shared_from_this(),
packet = std::move(packet)]() mutable {
bool idle = self->m_write_queue.empty();
@@ -115,6 +127,9 @@ void NetworkClient::send(std::shared_ptr<std::vector<uint8_t>> packet) {
}
void NetworkClient::do_write() {
if (m_closed.load()) {
return;
}
auto self = shared_from_this();
asio::async_write(
@@ -142,6 +157,17 @@ void NetworkClient::close() {
m_socket.shutdown(tcp::socket::shutdown_both, ec);
m_socket.close(ec);
Logger::info("NetworkClient Closed");
m_connected = false;
m_io.stop();
}
void NetworkClient::stop() {
close();
if (m_net_thread.joinable()) {
m_net_thread.join();
}
}
} // namespace Cubed

View File

@@ -32,9 +32,11 @@ void NetworkServer::stop() {
}
if (m_net_thread.joinable()) {
Logger::info("Server join thread={}, current={}", m_net_thread.get_id(),
std::this_thread::get_id());
m_net_thread.join();
}
Logger::info("Server Stopped!");
Logger::info("Server Net Thread Stopped!");
}
asio::awaitable<void> NetworkServer::listen() {

View File

@@ -32,6 +32,16 @@ void ServerWorld::wait_all_chunk_tasks() {
}
}
void ServerWorld::send_time() {
UpdateTime rsp;
rsp.set_day_tick(m_day_tick);
rsp.set_game_tick(m_game_ticks);
for (auto& [uuid, player] : m_players) {
player.get_session()->send(make_packet(rsp));
}
}
void ServerWorld::init_world() {
m_cave_carcer.init(ChunkGenerator::seed());
m_river_worm.init(ChunkGenerator::seed());
@@ -270,12 +280,17 @@ void ServerWorld::stop_thread_pool() {
void ServerWorld::serever_run(std::stop_token stoken) {
Logger::info("Server Thread Started!");
while (!stoken.stop_requested()) {
std::this_thread::sleep_for(milliseconds(m_per_tick_time));
auto t1 = system_clock::now();
if (m_tick_running) {
++m_game_ticks;
m_day_tick = (m_day_tick + 1) % DAY_TIME;
}
update();
auto t2 = system_clock::now();
auto dt = duration_cast<microseconds>(t2 - t1);
auto st = std::max(dt, milliseconds(m_per_tick_time) - dt);
std::this_thread::sleep_for(st);
}
Logger::info("Server Thread Stopped!");
}
@@ -373,6 +388,10 @@ void ServerWorld::update() {
m_could_gen = true;
}
}
send_time();
for (auto& [id, timer] : m_timers) {
timer.update();
}
}
void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,

View File

@@ -58,6 +58,7 @@ asio::awaitable<void> Session::read_loop() {
co_await asio::async_read(m_socket, asio::buffer(body_data),
asio::use_awaitable);
}
Logger::info("Session: Receive cmd {}", cmd_id);
constexpr auto& to_num = std::to_underlying<PacketEnum>;
if (cmd_id == to_num(PacketEnum::LOGIN_REQ)) {
LoginReq req;

View File

@@ -8,4 +8,5 @@ import "auth/auth.proto";
import "system/ping.proto";
import "system/pong.proto";
import "world/chunk_data.proto";
import "world/block_change.proto";
import "world/block_change.proto";
import "world/time.proto";

View File

@@ -0,0 +1,6 @@
syntax = "proto3";
message UpdateTime {
int64 game_tick = 1;
int64 day_tick = 2;
}