From e2bbc2d57f660ae62bd136bb37d1fff19c5858e4 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Tue, 4 Aug 2026 10:46:31 +0800 Subject: [PATCH] feat: sync entity direction and rotate models accordingly Move direction into the transform component and include it in server-to-client entity updates. Client now sets transform direction from the network message and uses it to compute yaw for model rotation, so entities visually face their movement direction. Refactor net_utils to support arbitrary Vec3 fields. --- include/Cubed/gameplay/client_entity_manager.hpp | 1 + include/Cubed/gameplay/ecs/server_entity.hpp | 2 -- include/Cubed/render/model_renderer.hpp | 6 ++++-- include/Cubed/tools/net_utils.hpp | 11 +++++++---- src/gameplay/client_entity_manager.cpp | 4 +++- src/gameplay/server_entity_manager.cpp | 3 +++ src/gameplay/server_world.cpp | 2 +- src/gameplay/systems/speed_system.cpp | 3 ++- src/gameplay/systems/wander_ai_system.cpp | 2 +- src/proto/world/entity.proto | 1 + src/render/model_renderer.cpp | 11 +++++++---- src/render/world_renderer.cpp | 9 +++++++-- 12 files changed, 37 insertions(+), 18 deletions(-) diff --git a/include/Cubed/gameplay/client_entity_manager.hpp b/include/Cubed/gameplay/client_entity_manager.hpp index 6d90d36..fc81b9a 100644 --- a/include/Cubed/gameplay/client_entity_manager.hpp +++ b/include/Cubed/gameplay/client_entity_manager.hpp @@ -35,6 +35,7 @@ private: struct UpdateInfo { EntityID id; glm::vec3 pos; + glm::vec3 direction; }; using EntityMap = tbb::concurrent_hash_map; diff --git a/include/Cubed/gameplay/ecs/server_entity.hpp b/include/Cubed/gameplay/ecs/server_entity.hpp index 23f064d..462e300 100644 --- a/include/Cubed/gameplay/ecs/server_entity.hpp +++ b/include/Cubed/gameplay/ecs/server_entity.hpp @@ -12,8 +12,6 @@ struct BaseServerCreature { Movement movement{}; - Direction direction{}; - Gravity gravity{}; Health health{}; diff --git a/include/Cubed/render/model_renderer.hpp b/include/Cubed/render/model_renderer.hpp index b6ae802..477249d 100644 --- a/include/Cubed/render/model_renderer.hpp +++ b/include/Cubed/render/model_renderer.hpp @@ -11,9 +11,11 @@ class Camera; class ModelRender { public: ModelRender(Renderer& renderer); - void render_model(ModelID id, const glm::vec3& pos, Camera& camera); + void render_model(ModelID id, const glm::vec3& pos, float yaw, + Camera& camera); - void shadow_pass(ModelID id, const glm::vec3& pos, Camera& camera); + void shadow_pass(ModelID id, const glm::vec3& pos, float yaw, + Camera& camera); private: Renderer& m_renderer; diff --git a/include/Cubed/tools/net_utils.hpp b/include/Cubed/tools/net_utils.hpp index aa05e9f..56c524e 100644 --- a/include/Cubed/tools/net_utils.hpp +++ b/include/Cubed/tools/net_utils.hpp @@ -5,16 +5,19 @@ #include "glm/ext/vector_float3.hpp" namespace Cubed { namespace Tools { -template void set_net_pos(T ptr, const glm::vec3& pos) { - Vec3* p = ptr->mutable_pos(); +inline void set_net_vec3(Vec3* p, const glm::vec3& pos) { p->set_x(pos.x); p->set_y(pos.y); p->set_z(pos.z); } -inline glm::vec3 get_net_pos(const Vec3* p) { +template void set_net_pos(T ptr, const glm::vec3& pos) { + set_net_vec3(ptr->mutable_pos(), pos); +} + +inline glm::vec3 get_net_vec3(const Vec3* p) { return glm::vec3{p->x(), p->y(), p->z()}; } -inline glm::vec3 get_net_pos(const Vec3& p) { +inline glm::vec3 get_net_vec3(const Vec3& p) { return glm::vec3{p.x(), p.y(), p.z()}; } } // namespace Tools diff --git a/src/gameplay/client_entity_manager.cpp b/src/gameplay/client_entity_manager.cpp index 46a8c66..c9db176 100644 --- a/src/gameplay/client_entity_manager.cpp +++ b/src/gameplay/client_entity_manager.cpp @@ -49,6 +49,7 @@ void ClientEntityManager::handle_entity_update(UpdateInfo& info) { auto creature = m_registry.try_get(e); ASSERT(creature); creature->transform.position.value = info.pos; + creature->transform.direction.value = info.direction; } void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) { @@ -66,7 +67,8 @@ void ClientEntityManager::receive_entity_destory(EntityID id) { void ClientEntityManager::receive_entity_update(S2CEntityUpdate& msg) { UpdateInfo e; e.id = msg.id(); - e.pos = Tools::get_net_pos(msg.pos()); + e.pos = Tools::get_net_vec3(msg.pos()); + e.direction = Tools::get_net_vec3(msg.direction()); m_tasks.emplace(Command::UPDATE, std::move(e)); } diff --git a/src/gameplay/server_entity_manager.cpp b/src/gameplay/server_entity_manager.cpp index 22a0dce..6a2b082 100644 --- a/src/gameplay/server_entity_manager.cpp +++ b/src/gameplay/server_entity_manager.cpp @@ -56,6 +56,9 @@ void ServerEntityManager::update_send() { p->set_id(entity.id); Tools::set_net_pos(p, creature.transform.position.value); + Tools::set_net_vec3(p->mutable_direction(), + creature.transform.direction.value); + for (auto& s : sessions) { s->send(make_packet(p)); } diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 1e18407..8d1af71 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -875,7 +875,7 @@ 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())); + m_entity_manager.add_entity(req.name(), Tools::get_net_vec3(req.pos())); } void ServerWorld::handle_entity_destory(C2SEntityDestoryRequest& req) { m_entity_manager.destory(req.id()); diff --git a/src/gameplay/systems/speed_system.cpp b/src/gameplay/systems/speed_system.cpp index 7b25f6c..68e1cb4 100644 --- a/src/gameplay/systems/speed_system.cpp +++ b/src/gameplay/systems/speed_system.cpp @@ -13,7 +13,8 @@ void SpeedSystem::update(float dt, entt::registry& registry) { auto& v = creature.velocity.value; if (moveboost.count <= moveboost.duration) { ++moveboost.count; - v += creature.direction.value * creature.movement.acceleration; + v += creature.transform.direction.value * + creature.movement.acceleration; } else { // Decelerated by friction in all directions auto decay = [](float& c, float d) { diff --git a/src/gameplay/systems/wander_ai_system.cpp b/src/gameplay/systems/wander_ai_system.cpp index d2aefd3..3a4e570 100644 --- a/src/gameplay/systems/wander_ai_system.cpp +++ b/src/gameplay/systems/wander_ai_system.cpp @@ -29,7 +29,7 @@ void WanderAISystem::do_ai(BaseServerCreature& creature, MoveBoost& move_boost) { thread_local Random r{std::random_device()()}; if (r.random_bool(DIRECTION_PROBABILITY)) { - creature.direction.value = r.random_direction_horizontal(); + creature.transform.direction.value = r.random_direction_horizontal(); } if (r.random_bool(MOVE_PROBABILITY)) { diff --git a/src/proto/world/entity.proto b/src/proto/world/entity.proto index 99fb89f..c7a1e7e 100644 --- a/src/proto/world/entity.proto +++ b/src/proto/world/entity.proto @@ -26,4 +26,5 @@ message C2SEntityCreateRequest { message S2CEntityUpdate { uint64 id = 1; Vec3 pos = 2; + Vec3 direction = 3; } \ No newline at end of file diff --git a/src/render/model_renderer.cpp b/src/render/model_renderer.cpp index 66bc4fd..2c56729 100644 --- a/src/render/model_renderer.cpp +++ b/src/render/model_renderer.cpp @@ -6,20 +6,23 @@ namespace Cubed { ModelRender::ModelRender(Renderer& renderer) : m_renderer(renderer) {} -void ModelRender::render_model(ModelID id, const glm::vec3& pos, +void ModelRender::render_model(ModelID id, const glm::vec3& pos, float yaw, Camera& camera) { auto& root = ModelManager::model(id).node; - glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos); + glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * + glm::rotate(glm::mat4(1.0f), yaw, {0, 1, 0}); auto& shader = m_renderer.get_shader("model_shader"); glm::mat4 view = camera.get_camera_lookat(); shader.set_loc("proj_matrix", m_renderer.p_mat()); render_node(root, transform, view, shader, false); } -void ModelRender::shadow_pass(ModelID id, const glm::vec3& pos, +void ModelRender::shadow_pass(ModelID id, const glm::vec3& pos, float yaw, Camera& camera) { auto& root = ModelManager::model(id).node; - glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos); + glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * + glm::rotate(glm::mat4(1.0f), yaw, {0, 1, 0}); + auto& shader = m_renderer.get_shader("depth_model"); glm::mat4 view = camera.get_camera_lookat(); diff --git a/src/render/world_renderer.cpp b/src/render/world_renderer.cpp index 9920e9c..7bc33fc 100644 --- a/src/render/world_renderer.cpp +++ b/src/render/world_renderer.cpp @@ -300,8 +300,11 @@ void WorldRenderer::shadow_entity(ClientWorld& world, auto view = registry.view(); for (auto entity : view) { auto& creature = view.get(entity); + float yaw = std::atan2(creature.transform.direction.value.x, + creature.transform.direction.value.z); + m_renderer.model_renderer().shadow_pass( - creature.model, creature.transform.position.value, + creature.model, creature.transform.position.value, yaw, world.world_scene().camera()); } m_player_renderer.render(shader, world, true); @@ -721,8 +724,10 @@ void WorldRenderer::render_entity(ClientWorld& world) { auto view = registry.view(); for (auto entity : view) { auto& creature = view.get(entity); + float yaw = std::atan2(creature.transform.direction.value.x, + creature.transform.direction.value.z); m_renderer.model_renderer().render_model( - creature.model, creature.transform.position.value, + creature.model, creature.transform.position.value, yaw, world.world_scene().camera()); }