mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(entity): add client-to-server entity creation and destruction requests
Extend the network protocol with `C2SEntityCreateRequest` and `C2SEntityDestoryRequest` packets. Refactor entity managers to split public client-facing create/destroy methods that send requests over the network, from internal handlers that process received packets. Add utility functions for converting protobuf Vec3 to glm::vec3.
This commit is contained in:
@@ -15,11 +15,13 @@ public:
|
|||||||
ClientEntityManager(ClientWorld& world);
|
ClientEntityManager(ClientWorld& world);
|
||||||
void update();
|
void update();
|
||||||
void init();
|
void init();
|
||||||
// not thread safe
|
|
||||||
void add_entity(EntityID id, std::string_view name, const glm::vec3& pos);
|
|
||||||
|
|
||||||
void receive_entity_create(S2CEntityCreate& s2c);
|
void receive_entity_create(S2CEntityCreate& s2c);
|
||||||
|
void receive_entity_destory(EntityID id);
|
||||||
|
|
||||||
void destory(EntityID id);
|
void destory(EntityID id);
|
||||||
|
void create(std::string_view name, const glm::vec3& pos);
|
||||||
|
|
||||||
const entt::registry& get_registry() const;
|
const entt::registry& get_registry() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -43,6 +45,9 @@ private:
|
|||||||
|
|
||||||
void handle_task();
|
void handle_task();
|
||||||
void handle_entity_destory(EntityID id);
|
void handle_entity_destory(EntityID id);
|
||||||
|
// not thread safe
|
||||||
|
void handle_entity_create(EntityID id, std::string_view name,
|
||||||
|
const glm::vec3& pos);
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void create_entity_in_registry(EntityID id, Args&&... args) {
|
void create_entity_in_registry(EntityID id, Args&&... args) {
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ public:
|
|||||||
WorldScene& world_scene();
|
WorldScene& world_scene();
|
||||||
ClientPlayerManager& player_manager();
|
ClientPlayerManager& player_manager();
|
||||||
ClientEntityManager& entity_manager();
|
ClientEntityManager& entity_manager();
|
||||||
|
std::shared_ptr<NetworkClient> get_client() const;
|
||||||
void set_direct_exit();
|
void set_direct_exit();
|
||||||
|
|
||||||
void receive_chat_message(ChatMsg& msg);
|
void receive_chat_message(ChatMsg& msg);
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ enum class PacketEnum : uint16_t {
|
|||||||
UPDATE_TIME = 3006,
|
UPDATE_TIME = 3006,
|
||||||
S2C_ENTITY_CREATE = 3007,
|
S2C_ENTITY_CREATE = 3007,
|
||||||
S2C_ENTITY_DESTORY = 3008,
|
S2C_ENTITY_DESTORY = 3008,
|
||||||
|
C2S_ENTITY_CREATE_REQUEST = 3009,
|
||||||
|
C2S_ENTITY_DESTORY_REQUEST = 3010,
|
||||||
CHAT_MSG = 4001,
|
CHAT_MSG = 4001,
|
||||||
VOICE_MSG = 4002,
|
VOICE_MSG = 4002,
|
||||||
PING = 9001,
|
PING = 9001,
|
||||||
@@ -119,6 +121,12 @@ template <> constexpr uint16_t get_packet_id<S2CEntityCreate>() {
|
|||||||
template <> constexpr uint16_t get_packet_id<S2CEntityDestory>() {
|
template <> constexpr uint16_t get_packet_id<S2CEntityDestory>() {
|
||||||
return std::to_underlying(PacketEnum::S2C_ENTITY_DESTORY);
|
return std::to_underlying(PacketEnum::S2C_ENTITY_DESTORY);
|
||||||
}
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<C2SEntityCreateRequest>() {
|
||||||
|
return std::to_underlying(PacketEnum::C2S_ENTITY_CREATE_REQUEST);
|
||||||
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<C2SEntityDestoryRequest>() {
|
||||||
|
return std::to_underlying(PacketEnum::C2S_ENTITY_DESTORY_REQUEST);
|
||||||
|
}
|
||||||
template <> constexpr uint16_t get_packet_id<UpdateTime>() {
|
template <> constexpr uint16_t get_packet_id<UpdateTime>() {
|
||||||
return std::to_underlying(PacketEnum::UPDATE_TIME);
|
return std::to_underlying(PacketEnum::UPDATE_TIME);
|
||||||
}
|
}
|
||||||
@@ -188,6 +196,12 @@ Packet make_packet(const T& msg) {
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::derived_from<T, google::protobuf::Message>
|
||||||
|
Packet make_packet(const T* msg) {
|
||||||
|
return make_packet(*msg);
|
||||||
|
}
|
||||||
|
|
||||||
inline PacketHeader decode_packet_header(std::span<const uint8_t> header) {
|
inline PacketHeader decode_packet_header(std::span<const uint8_t> header) {
|
||||||
if (header.size() < HEADER_LEN)
|
if (header.size() < HEADER_LEN)
|
||||||
throw std::runtime_error("Invalid header");
|
throw std::runtime_error("Invalid header");
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ private:
|
|||||||
void handle_entity_destory(EntityID id);
|
void handle_entity_destory(EntityID id);
|
||||||
void handle_task();
|
void handle_task();
|
||||||
void send_all_entities(std::shared_ptr<Session>& session);
|
void send_all_entities(std::shared_ptr<Session>& session);
|
||||||
template <typename... Args> EntityID add_entity(Args&&... args) {
|
template <typename... Args>
|
||||||
|
EntityID create_entity_in_factory(Args&&... args) {
|
||||||
auto entity = m_registry.create();
|
auto entity = m_registry.create();
|
||||||
|
|
||||||
((m_registry.emplace<std::remove_cvref_t<Args>>(
|
((m_registry.emplace<std::remove_cvref_t<Args>>(
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ public:
|
|||||||
|
|
||||||
void handle_chat_message(ChatMsg& msg);
|
void handle_chat_message(ChatMsg& msg);
|
||||||
void handle_voice_message(VoiceMsg& msg);
|
void handle_voice_message(VoiceMsg& msg);
|
||||||
|
|
||||||
|
void handle_entity_create(C2SEntityCreateRequest& req);
|
||||||
|
void handle_entity_destory(C2SEntityDestoryRequest& req);
|
||||||
|
|
||||||
int chunk_size() const;
|
int chunk_size() const;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Session>> get_all_session() const;
|
std::vector<std::shared_ptr<Session>> get_all_session() const;
|
||||||
|
|||||||
@@ -11,5 +11,11 @@ template <Ptr T> void set_net_pos(T ptr, const glm::vec3& pos) {
|
|||||||
p->set_y(pos.y);
|
p->set_y(pos.y);
|
||||||
p->set_z(pos.z);
|
p->set_z(pos.z);
|
||||||
}
|
}
|
||||||
|
inline glm::vec3 get_net_pos(const Vec3* p) {
|
||||||
|
return glm::vec3{p->x(), p->y(), p->z()};
|
||||||
|
}
|
||||||
|
inline glm::vec3 get_net_pos(const Vec3& p) {
|
||||||
|
return glm::vec3{p.x(), p.y(), p.z()};
|
||||||
|
}
|
||||||
} // namespace Tools
|
} // namespace Tools
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -7,6 +7,10 @@
|
|||||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||||
#include "Cubed/render/model_manager.hpp"
|
#include "Cubed/render/model_manager.hpp"
|
||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
|
#include "Cubed/tools/net_utils.hpp"
|
||||||
|
|
||||||
|
using namespace google::protobuf;
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
ClientEntityManager::ClientEntityManager(ClientWorld& world) : m_world(world) {}
|
ClientEntityManager::ClientEntityManager(ClientWorld& world) : m_world(world) {}
|
||||||
void ClientEntityManager::update() { handle_task(); }
|
void ClientEntityManager::update() { handle_task(); }
|
||||||
@@ -20,8 +24,9 @@ void ClientEntityManager::init() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// not thread safe
|
// not thread safe
|
||||||
void ClientEntityManager::add_entity(EntityID id, std::string_view name,
|
void ClientEntityManager::handle_entity_create(EntityID id,
|
||||||
const glm::vec3& pos) {
|
std::string_view name,
|
||||||
|
const glm::vec3& pos) {
|
||||||
ASSERT(m_factories.contains(name));
|
ASSERT(m_factories.contains(name));
|
||||||
m_factories[name](id);
|
m_factories[name](id);
|
||||||
acc a;
|
acc a;
|
||||||
@@ -39,10 +44,28 @@ void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) {
|
|||||||
m_tasks.emplace(Command::CREATE, std::move(c));
|
m_tasks.emplace(Command::CREATE, std::move(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientEntityManager::destory(EntityID id) {
|
void ClientEntityManager::receive_entity_destory(EntityID id) {
|
||||||
m_tasks.emplace(Command::DESTORY, id);
|
m_tasks.emplace(Command::DESTORY, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientEntityManager::destory(EntityID id) {
|
||||||
|
auto client = m_world.get_client();
|
||||||
|
Arena arena;
|
||||||
|
auto* msg = Arena::Create<C2SEntityDestoryRequest>(&arena);
|
||||||
|
msg->set_id(id);
|
||||||
|
msg->set_uuid(m_world.get_player().get_uuid());
|
||||||
|
client->send(make_packet(*msg));
|
||||||
|
}
|
||||||
|
void ClientEntityManager::create(std::string_view name, const glm::vec3& pos) {
|
||||||
|
auto client = m_world.get_client();
|
||||||
|
Arena arena;
|
||||||
|
auto* msg = Arena::Create<C2SEntityCreateRequest>(&arena);
|
||||||
|
msg->set_name(name);
|
||||||
|
msg->set_uuid(m_world.get_player().get_uuid());
|
||||||
|
Tools::set_net_pos(msg, pos);
|
||||||
|
client->send(make_packet(msg));
|
||||||
|
}
|
||||||
|
|
||||||
void ClientEntityManager::handle_task() {
|
void ClientEntityManager::handle_task() {
|
||||||
TaskPair pair;
|
TaskPair pair;
|
||||||
while (m_tasks.try_pop(pair)) {
|
while (m_tasks.try_pop(pair)) {
|
||||||
@@ -50,7 +73,7 @@ void ClientEntityManager::handle_task() {
|
|||||||
case Command::CREATE: {
|
case Command::CREATE: {
|
||||||
auto* p = std::get_if<EntityCreateElement>(&pair.second);
|
auto* p = std::get_if<EntityCreateElement>(&pair.second);
|
||||||
ASSERT(p);
|
ASSERT(p);
|
||||||
add_entity(p->id, p->name, p->pos);
|
handle_entity_create(p->id, p->name, p->pos);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Command::DESTORY: {
|
case Command::DESTORY: {
|
||||||
|
|||||||
@@ -682,6 +682,9 @@ Config& ClientWorld::get_config() { return m_config; }
|
|||||||
WorldScene& ClientWorld::world_scene() { return m_world_scene; }
|
WorldScene& ClientWorld::world_scene() { return m_world_scene; }
|
||||||
ClientPlayerManager& ClientWorld::player_manager() { return m_player_manager; }
|
ClientPlayerManager& ClientWorld::player_manager() { return m_player_manager; }
|
||||||
ClientEntityManager& ClientWorld::entity_manager() { return m_entity_manager; }
|
ClientEntityManager& ClientWorld::entity_manager() { return m_entity_manager; }
|
||||||
|
std::shared_ptr<NetworkClient> ClientWorld::get_client() const {
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
void ClientWorld::set_direct_exit() { m_exit_direct = true; }
|
void ClientWorld::set_direct_exit() { m_exit_direct = true; }
|
||||||
void ClientWorld::request_exit() {
|
void ClientWorld::request_exit() {
|
||||||
if (m_receive_exit) {
|
if (m_receive_exit) {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
|||||||
case std::to_underlying(PacketEnum::S2C_ENTITY_DESTORY): {
|
case std::to_underlying(PacketEnum::S2C_ENTITY_DESTORY): {
|
||||||
auto* msg = Arena::Create<S2CEntityDestory>(&arena);
|
auto* msg = Arena::Create<S2CEntityDestory>(&arena);
|
||||||
if (decode_packet(*msg, body_data, header)) {
|
if (decode_packet(*msg, body_data, header)) {
|
||||||
m_world.entity_manager().destory(msg->id());
|
m_world.entity_manager().receive_entity_destory(msg->id());
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ void ServerEntityManager::init() {
|
|||||||
m_factories.try_emplace("cubed:pig", [this]() {
|
m_factories.try_emplace("cubed:pig", [this]() {
|
||||||
BaseServerCreature c;
|
BaseServerCreature c;
|
||||||
c.hitbox = HitboxManager::instance().get_hitbox_id("cubed:pig");
|
c.hitbox = HitboxManager::instance().get_hitbox_id("cubed:pig");
|
||||||
return add_entity(Entity{m_next}, EntityInfo{"cubed:pig", ""},
|
return create_entity_in_factory(Entity{m_next},
|
||||||
std::move(c), PigTag{});
|
EntityInfo{"cubed:pig", ""},
|
||||||
|
std::move(c), PigTag{});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
void ServerEntityManager::update() { handle_task(); }
|
void ServerEntityManager::update() { handle_task(); }
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Cubed/tools/cubed_assert.hpp"
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
#include "Cubed/tools/log.hpp"
|
#include "Cubed/tools/log.hpp"
|
||||||
#include "Cubed/tools/math_tools.hpp"
|
#include "Cubed/tools/math_tools.hpp"
|
||||||
|
#include "Cubed/tools/net_utils.hpp"
|
||||||
#include "Cubed/tools/uuid.hpp"
|
#include "Cubed/tools/uuid.hpp"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
@@ -872,6 +873,14 @@ void ServerWorld::handle_block_change(const BlockChangeReq& req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServerWorld::handle_entity_create(C2SEntityCreateRequest& req) {
|
||||||
|
|
||||||
|
m_entity_manager.add_entity(req.name(), Tools::get_net_pos(req.pos()));
|
||||||
|
}
|
||||||
|
void ServerWorld::handle_entity_destory(C2SEntityDestoryRequest& req) {
|
||||||
|
m_entity_manager.destory(req.id());
|
||||||
|
}
|
||||||
|
|
||||||
int ServerWorld::rendering_distance() const {
|
int ServerWorld::rendering_distance() const {
|
||||||
return m_rendering_distance.load();
|
return m_rendering_distance.load();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,20 @@ asio::awaitable<void> Session::read_loop() {
|
|||||||
m_server_world.handle_voice_message(*msg);
|
m_server_world.handle_voice_message(*msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cmd_id ==
|
||||||
|
std::to_underlying(PacketEnum::C2S_ENTITY_CREATE_REQUEST)) {
|
||||||
|
auto* msg = Arena::Create<C2SEntityCreateRequest>(&arena);
|
||||||
|
if (decode_packet(*msg, body_data, header)) {
|
||||||
|
m_server_world.handle_entity_create(*msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cmd_id ==
|
||||||
|
std::to_underlying(PacketEnum::C2S_ENTITY_DESTORY_REQUEST)) {
|
||||||
|
auto* msg = Arena::Create<C2SEntityDestoryRequest>(&arena);
|
||||||
|
if (decode_packet(*msg, body_data, header)) {
|
||||||
|
m_server_world.handle_entity_destory(*msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const asio::system_error& e) {
|
} catch (const asio::system_error& e) {
|
||||||
auto ec = e.code();
|
auto ec = e.code();
|
||||||
|
|||||||
@@ -10,4 +10,15 @@ message S2CEntityCreate {
|
|||||||
|
|
||||||
message S2CEntityDestory {
|
message S2CEntityDestory {
|
||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message C2SEntityDestoryRequest {
|
||||||
|
string uuid = 1;
|
||||||
|
uint64 id = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message C2SEntityCreateRequest {
|
||||||
|
string uuid = 1;
|
||||||
|
string name = 2;
|
||||||
|
Vec3 pos = 3;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user