aboutsummaryrefslogtreecommitdiff
path: root/src/client/movement/movement.cc
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 21:57:46 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 21:57:46 +1100
commite4483eca01b48b943cd0461e24a74ae1a3139ed4 (patch)
treeed58c3c246e3af1af337697695d780aa31f6ad9a /src/client/movement/movement.cc
parent1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (diff)
Update to most recent version (old initial commit)
Diffstat (limited to 'src/client/movement/movement.cc')
-rw-r--r--src/client/movement/movement.cc162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/client/movement/movement.cc b/src/client/movement/movement.cc
new file mode 100644
index 0000000..8712f89
--- /dev/null
+++ b/src/client/movement/movement.cc
@@ -0,0 +1,162 @@
+#include "client/movement/movement.hh"
+
+namespace client {
+namespace movement {
+
+static std::optional<shared::world::block>
+maybe_get_block(const shared::math::coords& pos,
+ const client::world::chunks_t& chunks,
+ const glm::ivec3& block_pos) noexcept {
+ const auto find_it = chunks.find(pos);
+
+ if (find_it == std::end(chunks)) {
+ return std::nullopt;
+ }
+
+ if (!find_it->second.has_value()) {
+ return std::nullopt;
+ }
+
+ return find_it->second->get_block(block_pos);
+}
+
+static std::optional<shared::movement::blocks>
+maybe_make_blocks(const glm::vec3& local_pos,
+ const shared::math::coords& chunk_pos,
+ const client::world::chunks_t& chunks, const int width,
+ const int height) noexcept {
+
+ shared::movement::blocks blocks;
+
+ for (int x = -width; x <= width; ++x) {
+ for (int y = -height; y <= height; ++y) {
+ for (int z = -width; z <= width; ++z) {
+
+ const glm::ivec3 rel_pos =
+ glm::ivec3{x, y, z} + glm::ivec3{local_pos};
+
+ if (rel_pos.y < 0 ||
+ rel_pos.y >= shared::world::chunk::HEIGHT) {
+ continue;
+ }
+
+ const shared::math::coords norm_chunk_pos =
+ shared::world::chunk::get_normalised_chunk(
+ chunk_pos, rel_pos.x, rel_pos.z);
+ const glm::ivec3 norm_pos =
+ shared::world::chunk::get_normalised_coords(rel_pos);
+
+ const auto block =
+ maybe_get_block(norm_chunk_pos, chunks, norm_pos);
+
+ if (!block.has_value()) {
+ return std::nullopt;
+ }
+
+ const glm::vec3 pos = glm::vec3{rel_pos} - local_pos;
+
+ const shared::movement::aabb aabb = {
+ .min = glm::vec3{0.0f, 0.0f, 0.0f} + pos,
+ .max = glm::vec3{1.0f, 1.0f, 1.0f} + pos};
+ blocks.push_back(
+ shared::movement::block{.block = *block,
+ .aabb = aabb,
+ .chunk_pos = norm_chunk_pos,
+ .pos = norm_pos});
+ }
+ }
+ }
+
+ return blocks;
+}
+
+std::optional<shared::animate> move(const shared::moveable& moveable,
+ const world::chunks_t& chunks) noexcept {
+
+ const auto xy = shared::movement::get_move_xy(state::tickrate, moveable);
+ const auto blocks = maybe_make_blocks(
+ moveable.get_local_pos(), moveable.get_chunk_pos(), chunks, xy.x, xy.y);
+ if (!blocks.has_value()) {
+ return std::nullopt;
+ }
+
+ return shared::movement::move(moveable, *blocks, state::tickrate);
+}
+
+std::optional<std::pair<shared::math::coords, glm::ivec3>>
+interact(const shared::moveable& moveable, const interact_mode& mode,
+ const client::world::chunks_t& chunks) noexcept {
+ const auto blocks = maybe_make_blocks(
+ moveable.get_local_pos(), moveable.get_chunk_pos(), chunks, 5, 5);
+ if (!blocks.has_value()) {
+ return std::nullopt;
+ }
+
+ constexpr float epsilon = 0.001f;
+ const auto& aabb = moveable.get_aabb();
+ constexpr shared::movement::aabb ray_aabb = {
+ .min = {-epsilon, shared::player::EYE_HEIGHT - epsilon, -epsilon},
+ .max = {epsilon, shared::player::EYE_HEIGHT + epsilon, epsilon}};
+
+ const shared::movement::moving_aabb ray_moving_aabb{
+ .aabb = ray_aabb, .velocity = moveable.get_angles().to_dir()};
+
+ std::optional<
+ std::pair<shared::movement::moving_aabb_ret, shared::movement::block>>
+ best;
+ for (const auto& block : *blocks) {
+ if (block.block == shared::world::block::type::air) {
+ continue;
+ }
+ if (!shared::world::block::is_removable(block.block)) {
+ continue;
+ }
+
+ const auto intersect = shared::movement::intersect_moving_aabbs(
+ ray_moving_aabb,
+ shared::movement::moving_aabb{.aabb = block.aabb,
+ .velocity = {0.0f, 0.0f, 0.0f}});
+
+ constexpr float MAX_REACH = 3.8f;
+ if (!intersect.has_value() || intersect->time > MAX_REACH) {
+ continue;
+ }
+ if (best.has_value() && intersect->time > best->first.time) {
+ continue;
+ }
+
+ best = std::make_pair(*intersect, block);
+ }
+
+ if (!best.has_value()) {
+ return std::nullopt;
+ }
+
+ const auto& [intersect, block] = *best;
+
+ const glm::ivec3 position = block.pos;
+ if (mode == interact_mode::remove) {
+ return std::make_pair(block.chunk_pos, position);
+ }
+
+ const glm::ivec3 normal_i = -intersect.normal;
+ const glm::ivec3 normalised_pos =
+ shared::world::chunk::get_normalised_coords(normal_i + position);
+
+ const auto find_it =
+ std::find_if(std::begin(*blocks), std::end(*blocks),
+ [&](const auto b) { return b.pos == normalised_pos; });
+ if (find_it == std::end(*blocks)) {
+ return std::nullopt;
+ }
+ if (!shared::world::block::is_replaceable(find_it->block)) {
+ return std::nullopt;
+ }
+ if (shared::movement::intersect_aabbs(aabb, find_it->aabb)) {
+ return std::nullopt;
+ }
+ return std::make_pair(find_it->chunk_pos, normalised_pos);
+}
+
+} // namespace movement
+} // namespace client