mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(gameplay): add entity managers and refactor to ECS components
This commit is contained in:
@@ -100,4 +100,6 @@ target_sources(${PROJECT_NAME}
|
||||
gameplay/systems/physical_system.cpp
|
||||
gameplay/systems/speed_system.cpp
|
||||
gameplay/client_player_manager.cpp
|
||||
gameplay/server_entity_manager.cpp
|
||||
gameplay/client_entity_manager.cpp
|
||||
)
|
||||
53
src/gameplay/client_entity_manager.cpp
Normal file
53
src/gameplay/client_entity_manager.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "Cubed/gameplay/client_entity_manager.hpp"
|
||||
|
||||
#include "Cubed/gameplay/creatures/pig.hpp"
|
||||
#include "Cubed/gameplay/ecs/client_entity.hpp"
|
||||
#include "Cubed/gameplay/ecs/identity.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
#include "Cubed/render/model_manager.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
namespace Cubed {
|
||||
ClientEntityManager::ClientEntityManager(ClientWorld& world) : m_world(world) {}
|
||||
void ClientEntityManager::update() { handle_task(); }
|
||||
void ClientEntityManager::init() {
|
||||
m_factories.emplace("cubed:pig", [this](EntityID id) {
|
||||
BaseClientCreature c;
|
||||
c.model = ModelManager::instance().get_model_id("cubed:pig");
|
||||
add_entity(id, Entity{id}, EntityInfo{"cubed:pig", ""}, std::move(c),
|
||||
PigTag{});
|
||||
});
|
||||
}
|
||||
// not thread safe
|
||||
void ClientEntityManager::add_entity(EntityID id, std::string_view name,
|
||||
const glm::vec3& pos) {
|
||||
|
||||
m_factories[name](id);
|
||||
acc a;
|
||||
ASSERT(m_entities.find(a, id));
|
||||
auto* c = m_registry.try_get<Transform>(a->second);
|
||||
ASSERT(c);
|
||||
c->position.value = pos;
|
||||
}
|
||||
|
||||
void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) {
|
||||
EntityCreateElement c;
|
||||
c.id = s2c.id();
|
||||
c.name = s2c.name();
|
||||
c.pos = {s2c.pos().x(), s2c.pos().y(), s2c.pos().z()};
|
||||
m_tasks.emplace(Command::CREATE, std::move(c));
|
||||
}
|
||||
|
||||
void ClientEntityManager::handle_task() {
|
||||
TaskPair pair;
|
||||
while (m_tasks.try_pop(pair)) {
|
||||
switch (pair.first) {
|
||||
case Command::CREATE:
|
||||
auto* p = std::get_if<EntityCreateElement>(&pair.second);
|
||||
ASSERT(p);
|
||||
|
||||
add_entity(p->id, p->name, p->pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -1,4 +1,3 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/client_player_manager.hpp"
|
||||
|
||||
#include "Cubed/gameplay/client_world.hpp"
|
||||
|
||||
53
src/gameplay/server_entity_manager.cpp
Normal file
53
src/gameplay/server_entity_manager.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "Cubed/gameplay/server_entity_manager.hpp"
|
||||
|
||||
#include "Cubed/gameplay/creatures/pig.hpp"
|
||||
#include "Cubed/gameplay/ecs/identity.hpp"
|
||||
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||
#include "Cubed/gameplay/hitbox_manager.hpp"
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/net_utils.hpp"
|
||||
using namespace google::protobuf;
|
||||
|
||||
namespace Cubed {
|
||||
ServerEntityManager::ServerEntityManager(ServerWorld& world) : m_world(world) {}
|
||||
|
||||
void ServerEntityManager::init() {
|
||||
m_factories.try_emplace("cubed:pig", [this]() {
|
||||
BaseServerCreature c;
|
||||
c.hitbox = HitboxManager::instance().get_hitbox_id("cubed:pig");
|
||||
return add_entity(Entity{m_next}, EntityInfo{"cubed:pig", ""},
|
||||
std::move(c), PigTag{});
|
||||
});
|
||||
}
|
||||
|
||||
void ServerEntityManager::add_entity(std::string_view name,
|
||||
const glm::vec3& pos) {
|
||||
ASSERT(m_factories.contains(name));
|
||||
auto e = m_factories[name]();
|
||||
acc c;
|
||||
if (m_entities.find(c, e)) {
|
||||
auto t = m_registry.try_get<BaseServerCreature>(c->second);
|
||||
ASSERT(t);
|
||||
t->transform.position.value = pos;
|
||||
}
|
||||
send_entity_create(e, name, pos);
|
||||
}
|
||||
|
||||
void ServerEntityManager::send_entity_create(EntityID id, std::string_view name,
|
||||
const glm::vec3& pos) {
|
||||
auto sessions = m_world.get_all_session();
|
||||
|
||||
Arena arena;
|
||||
auto* s2c = Arena::Create<S2CEntityCreate>(&arena);
|
||||
s2c->set_id(id);
|
||||
s2c->set_name(name);
|
||||
Tools::set_net_pos(s2c, pos);
|
||||
|
||||
for (auto& s : sessions) {
|
||||
s->send(make_packet(*s2c));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -16,7 +16,8 @@ using namespace google::protobuf;
|
||||
namespace fs = std::filesystem;
|
||||
using nlohmann::json;
|
||||
namespace Cubed {
|
||||
ServerWorld::ServerWorld(Config& config) : m_config(config) {}
|
||||
ServerWorld::ServerWorld(Config& config)
|
||||
: m_config(config), m_entity_manager(*this) {}
|
||||
|
||||
ServerWorld::~ServerWorld() { stop(); }
|
||||
|
||||
@@ -85,7 +86,7 @@ void ServerWorld::send_time() {
|
||||
rsp->set_day_tick(m_day_tick);
|
||||
rsp->set_game_tick(m_game_ticks);
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
player.get_session()->send(make_packet(*rsp), 3);
|
||||
}
|
||||
@@ -96,7 +97,7 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid,
|
||||
ChunkPos pos) {
|
||||
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
return;
|
||||
@@ -159,7 +160,7 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid,
|
||||
}
|
||||
std::shared_ptr<Session> s;
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it != m_players.end()) {
|
||||
s = it->second.get_session();
|
||||
@@ -176,10 +177,12 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid,
|
||||
|
||||
void ServerWorld::init_world() {
|
||||
|
||||
m_entity_manager.init();
|
||||
|
||||
register_timer("player disconnect", 5, [this]() {
|
||||
std::vector<std::string> disconnect;
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
if (player.is_disconnect(m_game_ticks)) {
|
||||
disconnect.emplace_back(uuid);
|
||||
@@ -243,7 +246,7 @@ void ServerWorld::gen_chunks_internal(const std::string& uuid) {
|
||||
ChunkPosSet old_set;
|
||||
sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks_set);
|
||||
{
|
||||
std::lock_guard lock(m_player_mutex);
|
||||
std::lock_guard lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
return;
|
||||
@@ -564,7 +567,7 @@ void ServerWorld::sync_player_pos(const C2S_PlayerInfo& prsp) {
|
||||
auto yaw = prsp.yaw();
|
||||
auto pitch = prsp.pitch();
|
||||
{
|
||||
std::lock_guard lock(m_player_mutex);
|
||||
std::lock_guard lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
Logger::warn("Player {} is not in this Server", uuid);
|
||||
@@ -583,7 +586,7 @@ void ServerWorld::sync_player_pos(const C2S_PlayerInfo& prsp) {
|
||||
// update other player pos;
|
||||
std::vector<std::shared_ptr<Session>> other;
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [o_uuid, player] : m_players) {
|
||||
if (o_uuid == uuid) {
|
||||
continue;
|
||||
@@ -624,7 +627,7 @@ void ServerWorld::sync_player_water_sound(const PlayerWaterSound& rsp) {
|
||||
std::vector<std::shared_ptr<Session>> other;
|
||||
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [o_uuid, player] : m_players) {
|
||||
if (o_uuid == uuid) {
|
||||
continue;
|
||||
@@ -660,7 +663,7 @@ void ServerWorld::handle_player_login(const std::string& name,
|
||||
Logger::info("Player {} (uuid {}) join the world", name, uuid);
|
||||
bool sucess = true;
|
||||
{
|
||||
std::lock_guard lock(m_player_mutex);
|
||||
std::lock_guard lock(m_players_mutex);
|
||||
auto [_, inserted] = m_players.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(std::string(uuid)),
|
||||
std::forward_as_tuple(name, uuid, *this, session, m_game_ticks));
|
||||
@@ -710,7 +713,7 @@ void ServerWorld::handle_player_exit(const std::string& uuid) {
|
||||
ChunkPosSet old_set;
|
||||
std::string name;
|
||||
{
|
||||
std::lock_guard lock(m_player_mutex);
|
||||
std::lock_guard lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it != m_players.end()) {
|
||||
name = it->second.get_name();
|
||||
@@ -737,7 +740,7 @@ void ServerWorld::handle_player_exit(const std::string& uuid) {
|
||||
|
||||
std::vector<std::shared_ptr<Session>> sessions;
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
sessions.emplace_back(player.get_session());
|
||||
}
|
||||
@@ -754,7 +757,7 @@ void ServerWorld::handle_player_exit(const std::string& uuid) {
|
||||
}
|
||||
|
||||
glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
Logger::error("Can't find player uuid {}", uuid);
|
||||
@@ -766,7 +769,7 @@ glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
|
||||
void ServerWorld::handle_chunk_req(int task_id, const std::string& uuid,
|
||||
ChunkPos pos) {
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
return;
|
||||
@@ -804,7 +807,7 @@ void ServerWorld::handle_voice_message(VoiceMsg& msg) {
|
||||
std::vector<std::shared_ptr<Session>> session;
|
||||
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [key, player] : m_players) {
|
||||
if (key == uuid) {
|
||||
continue;
|
||||
@@ -851,7 +854,7 @@ void ServerWorld::handle_block_change(const BlockChangeReq& req) {
|
||||
std::vector<std::shared_ptr<Session>> sessions;
|
||||
auto chunk_pos = get_chunk_pos(x, z);
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
if (player.has_player(chunk_pos)) {
|
||||
auto session = player.get_session();
|
||||
@@ -934,7 +937,7 @@ void ServerWorld::send_server_stop() {
|
||||
Arena arena;
|
||||
auto* rsp = Arena::Create<LogoutRsp>(&arena);
|
||||
rsp->set_server_stop(true);
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
player.get_session()->send(make_packet(*rsp), 0);
|
||||
}
|
||||
@@ -947,7 +950,7 @@ void ServerWorld::boardcast_message(const std::string& name,
|
||||
|
||||
std::vector<std::shared_ptr<Session>> m_session;
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
for (auto& [_, p] : m_players) {
|
||||
m_session.emplace_back(p.get_session());
|
||||
}
|
||||
@@ -990,6 +993,15 @@ void ServerWorld::set_chunk_load_style(int id) {
|
||||
|
||||
int ServerWorld::chunk_size() const { return m_chunks.size(); }
|
||||
|
||||
std::vector<std::shared_ptr<Session>> ServerWorld::get_all_session() const {
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
std::vector<std::shared_ptr<Session>> sessions;
|
||||
for (const auto& [_, player] : m_players) {
|
||||
sessions.emplace_back(player.get_session());
|
||||
}
|
||||
return sessions;
|
||||
}
|
||||
|
||||
int ServerWorld::get_block(const glm::ivec3& block_pos) const {
|
||||
auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z);
|
||||
chunk_cacc cacc;
|
||||
|
||||
@@ -99,21 +99,6 @@ bool update_z(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
}
|
||||
|
||||
} // namespace
|
||||
std::tuple<bool, bool, bool> PhysicalSystem::update(float dt, ServerEntity& e,
|
||||
World& world) {
|
||||
glm::vec3 pos = e.transform.position.value;
|
||||
auto ans = update(dt, e, world, pos);
|
||||
e.transform.position.value = pos;
|
||||
return ans;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> PhysicalSystem::update(float dt, ServerEntity& e,
|
||||
World& world,
|
||||
glm::vec3& moved_pos) {
|
||||
|
||||
return update(dt, world, moved_pos, e.velocity, e.direction, e.move_state,
|
||||
e.hitbox);
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool>
|
||||
PhysicalSystem::update(float dt, World& world, glm::vec3& moved_pos,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "Cubed/gameplay/systems/speed_system.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
void SpeedSystem::update(float dt, ServerEntity& e) {
|
||||
update(dt, e.velocity, e.move_state, e.movement, e.direction, e.gravity);
|
||||
}
|
||||
|
||||
void SpeedSystem::update(float dt, Velocity& v, MoveState& move_state,
|
||||
Movement& movement, Direction& direction,
|
||||
|
||||
@@ -10,4 +10,5 @@ import "system/pong.proto";
|
||||
import "world/chunk_data.proto";
|
||||
import "world/block_change.proto";
|
||||
import "world/time.proto";
|
||||
import "world/entity.proto";
|
||||
import "chat/chat.proto";
|
||||
9
src/proto/world/entity.proto
Normal file
9
src/proto/world/entity.proto
Normal file
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common/vector3.proto";
|
||||
|
||||
message S2CEntityCreate {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
Vec3 pos = 3;
|
||||
}
|
||||
Reference in New Issue
Block a user