feat(protocol): add packet serialization and login handling

Introduce packet header and ID mapping for protobuf messages.
Refactor session and server_world to use new packet wrapper.
Fix missing semicolons in proto files.
This commit is contained in:
2026-06-23 21:58:35 +08:00
parent 678fc02998
commit 2953e8a233
9 changed files with 96 additions and 33 deletions

View File

@@ -158,6 +158,7 @@ protobuf_generate(
TARGET ${PROJECT_NAME}
LANGUAGE cpp
PROTOS ${PROTO_FILES}
IMPORT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/proto
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}")
@@ -190,7 +191,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE
)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_compile_definitions(${PROJECT_NAME} PRIVATE
ASIO_STANDALONE
ASIO_NO_DEPRECATED

View File

@@ -0,0 +1,59 @@
#pragma once
#include "packet.pb.h"
#include <netinet/in.h>
#include <type_traits>
namespace Cubed {
constexpr int HEADER_LEN = 8;
using Packet = std::shared_ptr<std::vector<uint8_t>>;
template <typename> struct always_false : std::false_type {}; // NOLINT
template <typename T> constexpr uint16_t get_packet_id() {
using std::is_same_v;
using U = std::decay_t<T>;
if constexpr (is_same_v<U, LoginReq>) {
return 1001;
} else if constexpr (is_same_v<U, LoginRsp>) {
return 1002;
} else if constexpr (is_same_v<U, PlayerInfo>) {
return 2001;
} else if constexpr (is_same_v<U, PlayerPos>) {
return 2002;
} else if constexpr (is_same_v<U, ChunkData>) {
return 3001;
} else if constexpr (is_same_v<U, Ping>) {
return 9001;
} else if (is_same_v<U, Pong>) {
return 9002;
} else {
static_assert(always_false<U>::value, "Unkonw Type");
}
}
template <typename T> Packet make_packet(const T& msg) {
std::string body;
if (!msg.SerializeToString(&body)) {
return {};
}
uint16_t cmd = get_packet_id<T>();
uint32_t total_len = HEADER_LEN + body.size();
auto packet = std::make_shared<std::vector<uint8_t>>(total_len);
uint32_t total_len_net = htonl(total_len);
uint16_t cmd_net = htons(cmd);
std::memcpy(packet->data(), &total_len_net, sizeof(total_len_net));
std::memcpy(packet->data() + sizeof(total_len_net), &cmd_net,
sizeof(cmd_net));
std::memcpy(packet->data() + HEADER_LEN, body.data(), body.size());
return packet;
}
} // namespace Cubed

View File

@@ -7,15 +7,16 @@
#include "Cubed/gameplay/server_chunk.hpp"
#include "Cubed/gameplay/server_player.hpp"
#include "Cubed/tools/thread_pool.hpp"
#include "proto/player_request.pb.h"
#include <future>
#include <shared_mutex>
#include <tbb/concurrent_hash_map.h>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
namespace Cubed {
class Session;
class ServerWorld {
public:
ServerWorld();
@@ -64,7 +65,8 @@ public:
void set_block(const glm::ivec3& block_pos, unsigned id);
void sync_player_pos(const std::string& name, float x, float y, float z);
void handle_player_request(const PlayerRequest& request);
void handle_player_login(const std::string& player_name,
std::shared_ptr<Session> session);
glm::vec3 get_player_pos(const std::string& name) const;
private:
@@ -119,6 +121,9 @@ private:
std::optional<std::string> m_request_gen_name = std::nullopt;
tbb::concurrent_hash_map<std::string, std::shared_ptr<Session>>
m_player_session;
void init_chunks();
void gen_chunks_internal();

View File

@@ -1,10 +1,13 @@
#pragma once
#include "Cubed/gameplay/packet.hpp"
#include <asio.hpp>
#include <deque>
#include <memory>
#include <string>
namespace Cubed {
using asio::ip::tcp;
class ServerWorld;
class Session : public std::enable_shared_from_this<Session> {
@@ -13,16 +16,15 @@ public:
Session(tcp::socket socket, ServerWorld& server_world);
~Session();
void start();
void send(std::shared_ptr<std::vector<uint8_t>> packet);
void send(Packet packet);
void close();
const std::string& uuid() const;
private:
static constexpr int HEADER_LEN = 8;
static constexpr uint32_t MAX_PACKET_SIZE = 4 * 1024 * 1024;
tcp::socket m_socket;
std::vector<char> m_read_buffer;
std::deque<std::shared_ptr<std::vector<uint8_t>>> m_write_queue;
std::deque<Packet> m_write_queue;
asio::strand<asio::io_context::executor_type> m_strand;
std::string m_uuid;
ServerWorld& m_server_world;

View File

@@ -1,6 +1,8 @@
#include "Cubed/gameplay/server_world.hpp"
#include "Cubed/config.hpp"
#include "Cubed/gameplay/packet.hpp"
#include "Cubed/gameplay/session.hpp"
#include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/log.hpp"
@@ -357,17 +359,14 @@ void ServerWorld::sync_player_pos(const std::string& name, float x, float y,
it->second.update_pos(x, y, z);
}
void ServerWorld::handle_player_request(const PlayerRequest& request) {
if (request.join()) {
player_join(request.name());
}
if (request.exit()) {
player_exit(request.name());
}
if (request.chunk_send()) {
m_request_gen_name = request.name();
need_gen();
}
void ServerWorld::handle_player_login(const std::string& name,
std::shared_ptr<Session> session) {
player_join(name);
m_player_session.emplace(name, session);
LoginRsp rsp;
rsp.set_success(true);
rsp.set_uuid(name);
session->send(make_packet(name));
}
void ServerWorld::player_join(const std::string& name) {

View File

@@ -3,8 +3,6 @@
#include "Cubed/gameplay/server_world.hpp"
#include "Cubed/tools/log.hpp"
#include "Cubed/tools/uuid.hpp"
#include "proto/player_pos.pb.h"
#include "proto/player_request.pb.h"
using asio::ip::tcp;
namespace Cubed {
@@ -61,20 +59,8 @@ asio::awaitable<void> Session::read_loop() {
}
if (cmd_id == 1001) {
PlayerRequest player_request;
if (player_request.ParseFromArray(body_data.data(),
body_data.size())) {
}
}
if (cmd_id == 1002) {
PlayerPos player_pos;
if (player_pos.ParseFromArray(body_data.data(),
body_data.size())) {
m_server_world.sync_player_pos(
player_pos.name(), player_pos.x(), player_pos.y(),
player_pos.z());
} else {
}
}
}
} catch (const asio::system_error& e) {

11
src/proto/packet.proto Normal file
View File

@@ -0,0 +1,11 @@
syntax = "proto3";
import "common/chunk_pos.proto";
import "common/error.proto";
import "common/player_info.proto";
import "common/vector3.proto";
import "player/player.proto";
import "auth/auth.proto";
import "system/ping.proto";
import "system/pong.proto";
import "world/chunk_data.proto";

View File

@@ -1,6 +1,6 @@
syntax = "proto3";
import "common/vector3.proto"
import "common/vector3.proto";
message PlayerPos {
string uuid = 1;

View File

@@ -1,6 +1,6 @@
syntax = "proto3";
import "common/chunk_pos.proto"
import "common/chunk_pos.proto";
message ChunkData {
ChunkPos pos = 1;