mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
Compare commits
4 Commits
d6f304e6ca
...
2e4a32fed7
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e4a32fed7 | |||
| c5ce91e653 | |||
| 412f88565a | |||
| 8451921161 |
@@ -10,14 +10,15 @@ namespace Cubed {
|
||||
class ClientWorld;
|
||||
class ClientEntityManager {
|
||||
public:
|
||||
enum class Command { CREATE, DESTORY };
|
||||
enum class Command { CREATE, DESTORY, UPDATE };
|
||||
|
||||
ClientEntityManager(ClientWorld& world);
|
||||
void update();
|
||||
void init();
|
||||
|
||||
void receive_entity_create(S2CEntityCreate& s2c);
|
||||
void receive_entity_create(S2CEntityCreate& msg);
|
||||
void receive_entity_destory(EntityID id);
|
||||
void receive_entity_update(S2CEntityUpdate& msg);
|
||||
|
||||
void destory(EntityID id);
|
||||
void create(std::string_view name, const glm::vec3& pos);
|
||||
@@ -30,11 +31,17 @@ private:
|
||||
std::string name;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
struct UpdateInfo {
|
||||
EntityID id;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
using EntityMap = tbb::concurrent_hash_map<EntityID, entt::entity>;
|
||||
using acc = EntityMap::accessor;
|
||||
using cacc = EntityMap::const_accessor;
|
||||
using CreateFunc = std::function<void(EntityID id)>;
|
||||
using TaskElement = std::variant<EntityCreateElement, EntityID>;
|
||||
using TaskElement = std::variant<EntityCreateElement, EntityID, UpdateInfo>;
|
||||
using TaskPair = std::pair<Command, TaskElement>;
|
||||
|
||||
ClientWorld& m_world;
|
||||
@@ -48,6 +55,7 @@ private:
|
||||
// not thread safe
|
||||
void handle_entity_create(EntityID id, std::string_view name,
|
||||
const glm::vec3& pos);
|
||||
void handle_entity_update(UpdateInfo& info);
|
||||
template <typename... Args>
|
||||
void create_entity_in_registry(EntityID id, Args&&... args) {
|
||||
{
|
||||
|
||||
17
include/Cubed/gameplay/ecs/ai_struct.hpp
Normal file
17
include/Cubed/gameplay/ecs/ai_struct.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/game_time.hpp"
|
||||
namespace Cubed {
|
||||
struct AIBase {
|
||||
TickType interval = 1;
|
||||
TickType count = 0;
|
||||
};
|
||||
|
||||
struct WanderAITag {};
|
||||
|
||||
struct MoveBoost {
|
||||
TickType duration = 0;
|
||||
TickType count = 0;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -3,10 +3,17 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
namespace Cubed {
|
||||
struct TickVelocity {
|
||||
|
||||
glm::vec3 value{0.0f};
|
||||
// blocks/tick!!! -1 for in
|
||||
glm::vec3 max{1.0f, -1.0f, 1.0f};
|
||||
};
|
||||
|
||||
struct Velocity {
|
||||
|
||||
glm::vec3 value{0.0f};
|
||||
|
||||
// blocks/second!!!
|
||||
glm::vec3 max{4.5f, 7.5f, 7.5f};
|
||||
};
|
||||
|
||||
@@ -23,4 +30,5 @@ struct Gravity {
|
||||
|
||||
float value = DEFAULT_G;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/health.hpp"
|
||||
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||
#include "Cubed/gameplay/ecs/state.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
#include "Cubed/gameplay/hitbox.hpp"
|
||||
namespace Cubed {
|
||||
@@ -9,12 +8,10 @@ namespace Cubed {
|
||||
struct BaseServerCreature {
|
||||
Transform transform{};
|
||||
|
||||
Velocity velocity{};
|
||||
TickVelocity velocity{};
|
||||
|
||||
Movement movement{};
|
||||
|
||||
MoveState move_state{};
|
||||
|
||||
Direction direction{};
|
||||
|
||||
Gravity gravity{};
|
||||
|
||||
@@ -149,12 +149,14 @@ private:
|
||||
|
||||
void update_direction();
|
||||
void update_lookup_block();
|
||||
|
||||
void update_move(float delta_time);
|
||||
|
||||
void update_move(float dt);
|
||||
void update_player_chunk();
|
||||
|
||||
void play_walk_sound(float dt);
|
||||
Gait compute_gait() const;
|
||||
|
||||
void update_speed(float dt);
|
||||
std::tuple<bool, bool, bool> update_physical(float dt, glm::vec3& pos);
|
||||
glm::vec3 get_move_distance(float dt);
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -51,10 +51,12 @@ enum class PacketEnum : uint16_t {
|
||||
LOGIN_RSP = 1002,
|
||||
LOGOUT_REQ = 1003,
|
||||
LOGOUT_RSP = 1004,
|
||||
|
||||
PLAYER_INFO = 2001,
|
||||
C2S_PLAYER_INFO = 2002,
|
||||
PLAYER_INFO_RSP = 2003,
|
||||
PLAYER_WATER_SOUND = 2004,
|
||||
|
||||
CHUNK_DATA_REQ = 3001,
|
||||
CHUNK_DATA_RSP = 3002,
|
||||
BLOCK_CHANGE_REQ = 3003,
|
||||
@@ -65,8 +67,11 @@ enum class PacketEnum : uint16_t {
|
||||
S2C_ENTITY_DESTORY = 3008,
|
||||
C2S_ENTITY_CREATE_REQUEST = 3009,
|
||||
C2S_ENTITY_DESTORY_REQUEST = 3010,
|
||||
S2C_ENTITY_UPDATE = 3011,
|
||||
|
||||
CHAT_MSG = 4001,
|
||||
VOICE_MSG = 4002,
|
||||
|
||||
PING = 9001,
|
||||
PONG = 9002
|
||||
|
||||
@@ -145,6 +150,9 @@ template <> constexpr uint16_t get_packet_id<ChatMsg>() {
|
||||
template <> constexpr uint16_t get_packet_id<VoiceMsg>() {
|
||||
return std::to_underlying(PacketEnum::VOICE_MSG);
|
||||
}
|
||||
template <> constexpr uint16_t get_packet_id<S2CEntityUpdate>() {
|
||||
return std::to_underlying(PacketEnum::S2C_ENTITY_UPDATE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::derived_from<T, google::protobuf::Message>
|
||||
|
||||
@@ -44,6 +44,8 @@ private:
|
||||
void handle_entity_destory(EntityID id);
|
||||
void handle_task();
|
||||
void send_all_entities(std::shared_ptr<Session>& session);
|
||||
void update_ai();
|
||||
void update_move();
|
||||
template <typename... Args>
|
||||
EntityID create_entity_in_factory(Args&&... args) {
|
||||
auto entity = m_registry.create();
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||
#include "Cubed/gameplay/ecs/state.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
#include "Cubed/gameplay/world.hpp"
|
||||
namespace Cubed {
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
namespace Cubed {
|
||||
class ServerWorld;
|
||||
class PhysicalSystem {
|
||||
public:
|
||||
static glm::vec3 get_move_distance(float dt, const Direction& d,
|
||||
const Velocity& v);
|
||||
static glm::vec3 get_move_distance(const Direction& d,
|
||||
const TickVelocity& v);
|
||||
|
||||
static std::tuple<bool, bool, bool>
|
||||
update(float dt, World& world, glm::vec3& moved_pos, Velocity& v,
|
||||
Direction& direction, MoveState& move_state, HitboxID hitbox);
|
||||
static void update(ServerWorld& world, entt::registry& registry);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||
#include "Cubed/gameplay/ecs/state.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
namespace Cubed {
|
||||
class SpeedSystem {
|
||||
public:
|
||||
static void update(float dt, Velocity& v, MoveState& move_state,
|
||||
Movement& movement, Direction& direction,
|
||||
const Gravity& g);
|
||||
static void update(float dt, entt::registry& registry);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
14
include/Cubed/gameplay/systems/wander_ai_system.hpp
Normal file
14
include/Cubed/gameplay/systems/wander_ai_system.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/ai_struct.hpp"
|
||||
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
namespace Cubed {
|
||||
class WanderAISystem {
|
||||
public:
|
||||
static void update(entt::registry& registry);
|
||||
|
||||
private:
|
||||
static void do_ai(BaseServerCreature& creature, MoveBoost& move_boost);
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
#include "glm/ext/vector_float3.hpp"
|
||||
|
||||
#include <random>
|
||||
namespace Cubed {
|
||||
|
||||
@@ -14,6 +16,8 @@ public:
|
||||
int random_int(int min, int max);
|
||||
float random_float(float min, float max);
|
||||
|
||||
glm::vec3 random_direction_horizontal();
|
||||
|
||||
private:
|
||||
unsigned int m_seed = 0;
|
||||
std::mt19937 m_engine;
|
||||
|
||||
@@ -102,4 +102,5 @@ target_sources(${PROJECT_NAME}
|
||||
gameplay/client_player_manager.cpp
|
||||
gameplay/server_entity_manager.cpp
|
||||
gameplay/client_entity_manager.cpp
|
||||
gameplay/systems/wander_ai_system.cpp
|
||||
)
|
||||
@@ -36,8 +36,23 @@ void ClientEntityManager::handle_entity_create(EntityID id,
|
||||
c->transform.position.value = pos;
|
||||
}
|
||||
|
||||
void ClientEntityManager::handle_entity_update(UpdateInfo& info) {
|
||||
entt::entity e;
|
||||
{
|
||||
cacc a;
|
||||
if (m_entities.find(a, info.id)) {
|
||||
e = a->second;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto creature = m_registry.try_get<BaseClientCreature>(e);
|
||||
ASSERT(creature);
|
||||
creature->transform.position.value = info.pos;
|
||||
}
|
||||
|
||||
void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) {
|
||||
EntityCreateElement c;
|
||||
EntityCreateElement c{};
|
||||
c.id = s2c.id();
|
||||
c.name = s2c.name();
|
||||
c.pos = {s2c.pos().x(), s2c.pos().y(), s2c.pos().z()};
|
||||
@@ -48,6 +63,13 @@ void ClientEntityManager::receive_entity_destory(EntityID id) {
|
||||
m_tasks.emplace(Command::DESTORY, id);
|
||||
}
|
||||
|
||||
void ClientEntityManager::receive_entity_update(S2CEntityUpdate& msg) {
|
||||
UpdateInfo e;
|
||||
e.id = msg.id();
|
||||
e.pos = Tools::get_net_pos(msg.pos());
|
||||
m_tasks.emplace(Command::UPDATE, std::move(e));
|
||||
}
|
||||
|
||||
void ClientEntityManager::destory(EntityID id) {
|
||||
auto client = m_world.get_client();
|
||||
Arena arena;
|
||||
@@ -81,6 +103,11 @@ void ClientEntityManager::handle_task() {
|
||||
ASSERT(p);
|
||||
handle_entity_destory(*p);
|
||||
} break;
|
||||
case Command::UPDATE: {
|
||||
auto* p = std::get_if<UpdateInfo>(&pair.second);
|
||||
ASSERT(p);
|
||||
handle_entity_update(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,110 @@
|
||||
#include "Cubed/debug_collector.hpp"
|
||||
#include "Cubed/gameplay/client_world.hpp"
|
||||
#include "Cubed/gameplay/hitbox_manager.hpp"
|
||||
#include "Cubed/gameplay/systems/physical_system.hpp"
|
||||
#include "Cubed/gameplay/systems/speed_system.hpp"
|
||||
namespace {} // namespace
|
||||
|
||||
namespace Cubed {
|
||||
LocalPlayer::LocalPlayer(ClientWorld& world) : m_world(world) {}
|
||||
|
||||
namespace {
|
||||
|
||||
bool update_x(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ClientWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.x += distance.x;
|
||||
Hitbox b = box;
|
||||
b.center += p;
|
||||
glm::vec3 min = b.min();
|
||||
glm::vec3 max = b.max();
|
||||
int minx = std::floor(min.x);
|
||||
int maxx = std::floor(max.x);
|
||||
int miny = std::floor(min.y);
|
||||
int maxy = std::floor(max.y);
|
||||
int minz = std::floor(min.z);
|
||||
int maxz = std::floor(max.z);
|
||||
|
||||
for (int x = minx; x <= maxx; ++x) {
|
||||
for (int y = miny; y <= maxy; ++y) {
|
||||
for (int z = minz; z <= maxz; ++z) {
|
||||
glm::ivec3 block_pos{x, y, z};
|
||||
if (!world.can_pass_block(block_pos)) {
|
||||
Hitbox block_box = World::get_block_aabb(block_pos);
|
||||
if (b.intersects(block_box)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_y(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ClientWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.y += distance.y;
|
||||
Hitbox b = box;
|
||||
b.center += p;
|
||||
glm::vec3 min = b.min();
|
||||
glm::vec3 max = b.max();
|
||||
int minx = std::floor(min.x);
|
||||
int maxx = std::floor(max.x);
|
||||
int miny = std::floor(min.y);
|
||||
int maxy = std::floor(max.y);
|
||||
int minz = std::floor(min.z);
|
||||
int maxz = std::floor(max.z);
|
||||
|
||||
for (int x = minx; x <= maxx; ++x) {
|
||||
for (int y = miny; y <= maxy; ++y) {
|
||||
for (int z = minz; z <= maxz; ++z) {
|
||||
glm::ivec3 block_pos{x, y, z};
|
||||
if (!world.can_pass_block(block_pos)) {
|
||||
Hitbox block_box = World::get_block_aabb(block_pos);
|
||||
if (b.intersects(block_box)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_z(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ClientWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.z += distance.z;
|
||||
Hitbox b = box;
|
||||
b.center += p;
|
||||
glm::vec3 min = b.min();
|
||||
glm::vec3 max = b.max();
|
||||
int minx = std::floor(min.x);
|
||||
int maxx = std::floor(max.x);
|
||||
int miny = std::floor(min.y);
|
||||
int maxy = std::floor(max.y);
|
||||
int minz = std::floor(min.z);
|
||||
int maxz = std::floor(max.z);
|
||||
|
||||
for (int x = minx; x <= maxx; ++x) {
|
||||
for (int y = miny; y <= maxy; ++y) {
|
||||
for (int z = minz; z <= maxz; ++z) {
|
||||
glm::ivec3 block_pos{x, y, z};
|
||||
if (!world.can_pass_block(block_pos)) {
|
||||
Hitbox block_box = World::get_block_aabb(block_pos);
|
||||
if (b.intersects(block_box)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LocalPlayer::LocalPlayer(ClientWorld& world) : m_world(world) {
|
||||
|
||||
m_hitbox = HitboxManager::instance().get_hitbox_id("cubed:player");
|
||||
}
|
||||
LocalPlayer::~LocalPlayer() {}
|
||||
|
||||
const glm::vec3& LocalPlayer::get_front() const { return m_front; }
|
||||
@@ -333,9 +431,9 @@ LocalPlayer::get_hotbar() const {
|
||||
return m_hotbar;
|
||||
}
|
||||
|
||||
void LocalPlayer::update_move(float delta_time) {
|
||||
void LocalPlayer::update_move(float dt) {
|
||||
// if frame rate less than 1 frame per second, don't update
|
||||
if (delta_time > 1.0f) {
|
||||
if (dt > 1.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -343,7 +441,7 @@ void LocalPlayer::update_move(float delta_time) {
|
||||
m_sprinting = false;
|
||||
}
|
||||
if (space_on) {
|
||||
space_on_time += delta_time;
|
||||
space_on_time += dt;
|
||||
if (space_on_time >= MAX_SPACE_ON_TIME) {
|
||||
space_on = false;
|
||||
space_on_time = 0.0f;
|
||||
@@ -360,8 +458,7 @@ void LocalPlayer::update_move(float delta_time) {
|
||||
glm::vec3{m_max_run_speed, m_max_y_speed, m_max_run_speed};
|
||||
}
|
||||
|
||||
SpeedSystem::update(delta_time, m_velocity, m_move_state, m_movement,
|
||||
m_direction, m_gravity);
|
||||
update_speed(dt);
|
||||
|
||||
update_direction();
|
||||
|
||||
@@ -374,12 +471,9 @@ void LocalPlayer::update_move(float delta_time) {
|
||||
}
|
||||
|
||||
if (m_game_mode == SPECTATOR) {
|
||||
player_pos += PhysicalSystem::get_move_distance(delta_time, m_direction,
|
||||
m_velocity);
|
||||
player_pos += get_move_distance(dt);
|
||||
} else {
|
||||
auto [x, y, z] =
|
||||
PhysicalSystem::update(delta_time, m_world, player_pos, m_velocity,
|
||||
m_direction, m_move_state, m_hitbox);
|
||||
auto [x, y, z] = update_physical(dt, player_pos);
|
||||
if (!x || !z) {
|
||||
m_sprinting = false;
|
||||
}
|
||||
@@ -406,7 +500,7 @@ void LocalPlayer::update_move(float delta_time) {
|
||||
}
|
||||
|
||||
for (auto& [key, timer] : m_timers) {
|
||||
timer.update(delta_time);
|
||||
timer.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +687,97 @@ void LocalPlayer::init(std::string_view name) {
|
||||
}
|
||||
}
|
||||
|
||||
void LocalPlayer::update_speed(float dt) {
|
||||
// calculate speed
|
||||
auto& v = m_velocity;
|
||||
if (m_move_state.forward || m_move_state.back || m_move_state.left ||
|
||||
m_move_state.right) {
|
||||
m_direction.value = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
v.value.x += m_movement.acceleration * dt;
|
||||
v.value.z += m_movement.acceleration * dt;
|
||||
if (v.value.x > v.max.x) {
|
||||
v.value.x = v.max.x;
|
||||
}
|
||||
if (v.value.z > v.max.z) {
|
||||
v.value.z = v.max.z;
|
||||
}
|
||||
} else {
|
||||
v.value.x += -m_movement.deceleration * dt;
|
||||
v.value.z += -m_movement.deceleration * dt;
|
||||
if (v.value.z < 0.0f) {
|
||||
v.value.z = 0.0f;
|
||||
}
|
||||
if (v.value.x < 0.0f) {
|
||||
v.value.x = 0.0f;
|
||||
}
|
||||
if (v.value.z < 0.0f && v.value.x < 0.0f) {
|
||||
m_direction.value = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
if (m_move_state.is_fly) {
|
||||
if (m_move_state.up) {
|
||||
v.value.y = v.max.y;
|
||||
}
|
||||
|
||||
if (m_move_state.down) {
|
||||
v.value.y = -v.max.y;
|
||||
}
|
||||
|
||||
if (!m_move_state.down && !m_move_state.up) {
|
||||
v.value.y = 0.0f;
|
||||
}
|
||||
} else {
|
||||
if (m_move_state.up && m_move_state.can_up) {
|
||||
v.value.y = m_movement.jump_power;
|
||||
m_move_state.can_up = false;
|
||||
}
|
||||
|
||||
v.value.y += -m_gravity.value * dt;
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool> LocalPlayer::update_physical(float dt,
|
||||
glm::vec3& pos) {
|
||||
|
||||
auto distance = get_move_distance(dt);
|
||||
auto box = HitboxManager::hitbox(m_hitbox);
|
||||
bool x = false;
|
||||
bool y = false;
|
||||
bool z = false;
|
||||
if (update_x(pos, distance, m_world, box.box)) {
|
||||
pos.x += distance.x;
|
||||
x = true;
|
||||
} else {
|
||||
m_velocity.value.x = 0.0f;
|
||||
}
|
||||
|
||||
if (update_y(pos, distance, m_world, box.box)) {
|
||||
pos.y += distance.y;
|
||||
y = true;
|
||||
} else {
|
||||
m_velocity.value.y = 0.0f;
|
||||
if (distance.y < 0) {
|
||||
m_move_state.can_up = true;
|
||||
m_move_state.is_fly = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_z(pos, distance, m_world, box.box)) {
|
||||
pos.z += distance.z;
|
||||
z = true;
|
||||
} else {
|
||||
m_velocity.value.z = 0.0f;
|
||||
}
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
glm::vec3 LocalPlayer::get_move_distance(float dt) {
|
||||
const auto& d = m_direction;
|
||||
const auto& v = m_velocity;
|
||||
return glm::vec3{d.value.x * v.value.x * dt, v.value.y * dt,
|
||||
d.value.z * v.value.z * dt};
|
||||
}
|
||||
|
||||
bool LocalPlayer::is_underwater() const { return m_underwater; }
|
||||
void LocalPlayer::set_underwater(bool u) { m_underwater = u; }
|
||||
|
||||
|
||||
@@ -156,6 +156,12 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
||||
m_world.entity_manager().receive_entity_destory(msg->id());
|
||||
}
|
||||
} break;
|
||||
case std::to_underlying(PacketEnum::S2C_ENTITY_UPDATE): {
|
||||
auto* msg = Arena::Create<S2CEntityUpdate>(&arena);
|
||||
if (decode_packet(*msg, body_data, header)) {
|
||||
m_world.entity_manager().receive_entity_update(*msg);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} catch (const asio::system_error& e) {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "Cubed/gameplay/hitbox_manager.hpp"
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
#include "Cubed/gameplay/systems/physical_system.hpp"
|
||||
#include "Cubed/gameplay/systems/speed_system.hpp"
|
||||
#include "Cubed/gameplay/systems/wander_ai_system.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/net_utils.hpp"
|
||||
using namespace google::protobuf;
|
||||
@@ -22,8 +25,18 @@ void ServerEntityManager::init() {
|
||||
std::move(c), PigTag{});
|
||||
});
|
||||
}
|
||||
void ServerEntityManager::update() { handle_task(); }
|
||||
void ServerEntityManager::update() {
|
||||
handle_task();
|
||||
update_ai();
|
||||
update_move();
|
||||
}
|
||||
|
||||
void ServerEntityManager::update_ai() { WanderAISystem::update(m_registry); }
|
||||
void ServerEntityManager::update_move() {
|
||||
SpeedSystem::update(
|
||||
static_cast<float>(m_world.get_per_tick_time()) / 1000.0f, m_registry);
|
||||
PhysicalSystem::update(m_world, m_registry);
|
||||
}
|
||||
void ServerEntityManager::handle_task() {
|
||||
TaskPair pair;
|
||||
while (m_tasks.try_pop(pair)) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#include "Cubed/gameplay/systems/physical_system.hpp"
|
||||
|
||||
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||
#include "Cubed/gameplay/hitbox_manager.hpp"
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
namespace Cubed {
|
||||
|
||||
namespace {
|
||||
|
||||
bool update_x(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
const Hitbox& box) {
|
||||
bool update_x(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ServerWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.x += distance.x;
|
||||
Hitbox b = box;
|
||||
@@ -36,8 +38,8 @@ bool update_x(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_y(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
const Hitbox& box) {
|
||||
bool update_y(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ServerWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.y += distance.y;
|
||||
Hitbox b = box;
|
||||
@@ -67,8 +69,8 @@ bool update_y(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_z(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
const Hitbox& box) {
|
||||
bool update_z(const glm::vec3& pos, const glm::vec3& distance,
|
||||
ServerWorld& world, const Hitbox& box) {
|
||||
glm::vec3 p = pos;
|
||||
p.z += distance.z;
|
||||
Hitbox b = box;
|
||||
@@ -100,45 +102,41 @@ bool update_z(const glm::vec3& pos, const glm::vec3& distance, World& world,
|
||||
|
||||
} // namespace
|
||||
|
||||
std::tuple<bool, bool, bool>
|
||||
PhysicalSystem::update(float dt, World& world, glm::vec3& moved_pos,
|
||||
Velocity& v, Direction& direction, MoveState& move_state,
|
||||
HitboxID hitbox) {
|
||||
auto distance = get_move_distance(dt, direction, v);
|
||||
auto box = HitboxManager::hitbox(hitbox);
|
||||
bool x = false;
|
||||
bool y = false;
|
||||
bool z = false;
|
||||
if (update_x(moved_pos, distance, world, box.box)) {
|
||||
moved_pos.x += distance.x;
|
||||
x = true;
|
||||
void PhysicalSystem::update(ServerWorld& world, entt::registry& registry) {
|
||||
|
||||
auto view = registry.view<BaseServerCreature>();
|
||||
for (auto e : view) {
|
||||
auto& creature = view.get<BaseServerCreature>(e);
|
||||
auto distance =
|
||||
get_move_distance(creature.direction, creature.velocity);
|
||||
auto box = HitboxManager::hitbox(creature.hitbox);
|
||||
auto& pos = creature.transform.position.value;
|
||||
auto& v = creature.velocity;
|
||||
if (update_x(pos, distance, world, box.box)) {
|
||||
pos.x += distance.x;
|
||||
|
||||
} else {
|
||||
v.value.x = 0.0f;
|
||||
}
|
||||
|
||||
if (update_y(moved_pos, distance, world, box.box)) {
|
||||
moved_pos.y += distance.y;
|
||||
y = true;
|
||||
if (update_y(pos, distance, world, box.box)) {
|
||||
pos.y += distance.y;
|
||||
|
||||
} else {
|
||||
v.value.y = 0.0f;
|
||||
if (distance.y < 0) {
|
||||
move_state.can_up = true;
|
||||
move_state.is_fly = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_z(moved_pos, distance, world, box.box)) {
|
||||
moved_pos.z += distance.z;
|
||||
z = true;
|
||||
if (update_z(pos, distance, world, box.box)) {
|
||||
pos.z += distance.z;
|
||||
|
||||
} else {
|
||||
v.value.z = 0.0f;
|
||||
}
|
||||
return {x, y, z};
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 PhysicalSystem::get_move_distance(float dt, const Direction& d,
|
||||
const Velocity& v) {
|
||||
return glm::vec3{d.value.x * v.value.x * dt, v.value.y * dt,
|
||||
d.value.z * v.value.z * dt};
|
||||
glm::vec3 PhysicalSystem::get_move_distance(const Direction& d,
|
||||
const TickVelocity& v) {
|
||||
return glm::vec3{d.value.x * v.value.x, v.value.y, d.value.z * v.value.z};
|
||||
}
|
||||
} // namespace Cubed
|
||||
@@ -1,54 +1,24 @@
|
||||
#include "Cubed/gameplay/systems/speed_system.hpp"
|
||||
|
||||
#include "Cubed/gameplay/ecs/ai_struct.hpp"
|
||||
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
void SpeedSystem::update(float dt, Velocity& v, MoveState& move_state,
|
||||
Movement& movement, Direction& direction,
|
||||
const Gravity& g) {
|
||||
// calculate speed
|
||||
if (move_state.forward || move_state.back || move_state.left ||
|
||||
move_state.right) {
|
||||
direction.value = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
v.value.x += movement.acceleration * dt;
|
||||
v.value.z += movement.acceleration * dt;
|
||||
if (v.value.x > v.max.x) {
|
||||
v.value.x = v.max.x;
|
||||
}
|
||||
if (v.value.z > v.max.z) {
|
||||
v.value.z = v.max.z;
|
||||
}
|
||||
void SpeedSystem::update(float dt, entt::registry& registry) {
|
||||
auto view = registry.view<BaseServerCreature, MoveBoost>();
|
||||
|
||||
for (auto e : view) {
|
||||
auto [creature, moveboost] = view.get<BaseServerCreature, MoveBoost>(e);
|
||||
if (moveboost.count <= moveboost.duration) {
|
||||
++moveboost.count;
|
||||
creature.velocity.value +=
|
||||
creature.direction.value * creature.movement.acceleration;
|
||||
} else {
|
||||
v.value.x += -movement.deceleration * dt;
|
||||
v.value.z += -movement.deceleration * dt;
|
||||
if (v.value.z < 0.0f) {
|
||||
v.value.z = 0.0f;
|
||||
creature.velocity.value -=
|
||||
creature.direction.value * creature.movement.deceleration;
|
||||
}
|
||||
if (v.value.x < 0.0f) {
|
||||
v.value.x = 0.0f;
|
||||
}
|
||||
if (v.value.z < 0.0f && v.value.x < 0.0f) {
|
||||
direction.value = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
if (move_state.is_fly) {
|
||||
if (move_state.up) {
|
||||
v.value.y = v.max.y;
|
||||
}
|
||||
|
||||
if (move_state.down) {
|
||||
v.value.y = -v.max.y;
|
||||
}
|
||||
|
||||
if (!move_state.down && !move_state.up) {
|
||||
v.value.y = 0.0f;
|
||||
}
|
||||
} else {
|
||||
if (move_state.up && move_state.can_up) {
|
||||
v.value.y = movement.jump_power;
|
||||
move_state.can_up = false;
|
||||
}
|
||||
|
||||
v.value.y += -g.value * dt;
|
||||
creature.velocity.value.y = creature.gravity.value * dt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
src/gameplay/systems/wander_ai_system.cpp
Normal file
40
src/gameplay/systems/wander_ai_system.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "Cubed/gameplay/systems/wander_ai_system.hpp"
|
||||
|
||||
#include "Cubed/gameplay/ecs/ai_struct.hpp"
|
||||
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||
#include "Cubed/tools/cubed_random.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr double DIRECTION_PROBABILITY = 0.1;
|
||||
constexpr double MOVE_PROBABILITY = 0.1;
|
||||
} // namespace
|
||||
|
||||
namespace Cubed {
|
||||
void WanderAISystem::update(entt::registry& registry) {
|
||||
auto view =
|
||||
registry.view<AIBase, WanderAITag, BaseServerCreature, MoveBoost>();
|
||||
|
||||
for (auto e : view) {
|
||||
auto [ai, creature, move_boost] =
|
||||
view.get<AIBase, BaseServerCreature, MoveBoost>(e);
|
||||
++ai.count;
|
||||
if (ai.count >= ai.interval) {
|
||||
ai.count = 0;
|
||||
do_ai(creature, move_boost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
if (r.random_bool(MOVE_PROBABILITY)) {
|
||||
move_boost.duration = r.random_int(5, 8);
|
||||
move_boost.count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -22,3 +22,8 @@ message C2SEntityCreateRequest {
|
||||
string name = 2;
|
||||
Vec3 pos = 3;
|
||||
}
|
||||
|
||||
message S2CEntityUpdate {
|
||||
uint64 id = 1;
|
||||
Vec3 pos = 2;
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "Cubed/tools/cubed_random.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
namespace Cubed {
|
||||
|
||||
Random::Random() {}
|
||||
|
||||
Random::Random(unsigned seed) { init(seed); }
|
||||
bool Random::random_bool(double probability) {
|
||||
if (probability <= 0.0)
|
||||
@@ -44,4 +47,12 @@ float Random::random_float(float min, float max) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 Random::random_direction_horizontal() {
|
||||
float x = std::cos(random_float(0.0f, 2 * std::numbers::pi));
|
||||
float z = std::sin(random_float(0.0f, 2 * std::numbers::pi));
|
||||
|
||||
return glm::vec3{x, 0.0f, z};
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user