From ec467ca037e6deb978ff1fbda9799f6d17999fb2 Mon Sep 17 00:00:00 2001 From: Shu Date: Sun, 25 Oct 2020 11:22:32 +0100 Subject: [PATCH] Prevent suffocation --- README.md | 6 ++++-- TODO.md | 5 +++-- src/client/Client.cpp | 10 ++++++---- src/client/contouring/FlatDualMC.cpp | 10 ++++++++++ src/client/world/DistantUniverse.cpp | 12 ++++++++++++ src/client/world/DistantUniverse.hpp | 2 ++ src/client/world/LocalUniverse.cpp | 11 +++++++++++ src/client/world/LocalUniverse.hpp | 2 ++ src/core/data/generational.hpp | 10 ++++++++++ src/core/geometry/Shapes.hpp | 28 ++++++++++++++++++++++++++++ src/core/world/Universe.hpp | 5 +++++ src/core/world/actions.hpp | 13 ++++++++++++- src/server/world/SharedUniverse.cpp | 1 + src/server/world/Universe.cpp | 17 ++++++++++++++++- src/server/world/Universe.hpp | 2 ++ 15 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 src/core/geometry/Shapes.hpp diff --git a/README.md b/README.md index 347d7b4..3914284 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ cmake .. ``` CMake options: `-DKEY=VAL` + Key | Usage | Default --- | --- | --- SIMD_LEVEL | SIMD processor acceleration (sse2, sse4.1, avx2, avx512f) | `avx2` @@ -144,6 +145,7 @@ Distributed under the MIT License. See [LICENSE](LICENSE) for more information. ## Contact -Maelys Bois - [/me](https://git.wadza.fr/me) - me@wadza.fr +Shu - [/me](https://git.wadza.fr/me) - me@wadza.fr -Project Link: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel) +Public releases: [https://framagit.org/univerxel/univerxel](https://framagit.org/univerxel/univerxel) +Working repo: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel) diff --git a/TODO.md b/TODO.md index a08ae1e..53f9565 100644 --- a/TODO.md +++ b/TODO.md @@ -29,8 +29,8 @@ - Cube - Sphere - [ ] More types - - Anchor - - Prevent suffocation + - [ ] Anchor + - [x] Prevent suffocation - [ ] Local prediction - [~] Occlusion Culling - [ ] Iterator ray @@ -41,6 +41,7 @@ ## Hello universe + - [ ] CI build - [ ] Universe - [ ] Galaxy - [ ] Rotation diff --git a/src/client/Client.cpp b/src/client/Client.cpp index aa52f3a..e62010f 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -67,7 +67,7 @@ void Client::run(server_handle* const localHandle) { if(auto target = std::get_if(&ray_result)) { state.look_at = *target; const auto &tool = options.editor.tool; - state.can_fill = true; //FIXME: world->canFill(target->pos, tool.shape, tool.radius); + state.can_fill = world->isAreaFree(target->pos, world::action::ToGeometry(tool.shape), tool.radius); } else { state.look_at = {}; } @@ -79,9 +79,10 @@ void Client::run(server_handle* const localHandle) { if (inputs.isPressing(Mouse::Left)) world->emit(world::action::FillShape( state.look_at.value().pos, world::Voxel(world::materials::AIR, tool.emptyAir * world::Voxel::DENSITY_MAX), tool.shape, tool.radius)); - else if (inputs.isPressing(Mouse::Right)) + else if (const auto voxel = world::Voxel(tool.material, world::Voxel::DENSITY_MAX); + inputs.isPressing(Mouse::Right) && (state.can_fill || !voxel.is_solid())) world->emit(world::action::FillShape( - state.look_at.value().pos, world::Voxel(tool.material, world::Voxel::DENSITY_MAX), tool.shape, tool.radius)); + state.look_at.value().pos, voxel, tool.shape, tool.radius)); } if (inputs.isDown(Input::Throw)) { //FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)}); @@ -197,8 +198,9 @@ void Client::run(server_handle* const localHandle) { const auto pass = pipeline->beginIndicatorPass(); if(state.look_at.has_value()) { // Indicator const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2)); + const auto color = state.can_fill ? glm::vec4(1, 1, 1, .5) : (world::materials::solidity[options.editor.tool.material] ? glm::vec4(1, 0, 0, .5) : glm::vec4(1, .5, 0, .5)); reports.models_count++; - reports.tris_count += pass(model, options.editor.tool.shape, state.can_fill ? glm::vec4(1, 1, 1, .5) : glm::vec4(1, 0, 0, .5)); + reports.tris_count += pass(model, options.editor.tool.shape, color); } } pipeline->postProcess(); diff --git a/src/client/contouring/FlatDualMC.cpp b/src/client/contouring/FlatDualMC.cpp index 86b0c3f..2158b21 100644 --- a/src/client/contouring/FlatDualMC.cpp +++ b/src/client/contouring/FlatDualMC.cpp @@ -253,6 +253,16 @@ namespace contouring { } ImGui::Columns(1); } + if (ImGui::Button("Flush buffers")) { + //TODO: prefer unique_ptr + for(auto& buffer: buffers) { + for(auto& val: buffer.second.second) { + delete val.second.first; + delete val.second.second; + } + } + buffers.clear(); + } } void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector &tmp, Layer layer) const { diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index 933c33e..80dad2d 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -269,6 +269,18 @@ Universe::ray_result DistantUniverse::raycast(const geometry::Ray &ray) const { return Raycast(ray, areas); } +bool DistantUniverse::isAreaFree(const area_ &pos, const geometry::Shape shape, const uint16_t radius) const { + if (const auto it = areas.find(pos.first); it != areas.end()) { + const auto center = pos.second + it->second->getOffset().as_voxel(); + return !entities.contains([&](size_t, const Entity &entity) { + return entity.instances.contains([&](size_t, const Universe::Entity::Instance &inst) { + return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size); + }); + }); + } else + return false; +} + void DistantUniverse::getEntitiesModels(const std::function&)>& call, const std::optional& frustum, const glm::llvec3& offset, int density) { diff --git a/src/client/world/DistantUniverse.hpp b/src/client/world/DistantUniverse.hpp index 1b8e90e..b629a52 100644 --- a/src/client/world/DistantUniverse.hpp +++ b/src/client/world/DistantUniverse.hpp @@ -18,6 +18,8 @@ namespace world::client { ray_result raycast(const geometry::Ray &) const override; + bool isAreaFree(const area_ &pos, geometry::Shape shape, uint16_t radius) const override; + void getEntitiesModels(const std::function&)>&, const std::optional& frustum, const glm::llvec3& offset, int density) override; diff --git a/src/client/world/LocalUniverse.cpp b/src/client/world/LocalUniverse.cpp index a6cde3e..2f55b1f 100644 --- a/src/client/world/LocalUniverse.cpp +++ b/src/client/world/LocalUniverse.cpp @@ -55,6 +55,17 @@ void LocalUniverse::emit(const action::packet &packet) { Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const { return handle->raycast(ray); } +bool LocalUniverse::isAreaFree(const area_ &pos, const geometry::Shape shape, const uint16_t radius) const { + if (const auto it = handle->areas->find(pos.first); it != handle->areas->end()) { + const auto center = pos.second + it->second->getOffset().as_voxel(); + return !handle->entities->contains([&](entity_id, const Entity &entity) { + return entity.instances.contains([&](entity_id, const Entity::Instance &inst) { + return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size); + }); + }); + } else + return false; +} void LocalUniverse::getEntitiesModels(const std::function&)>& call, const std::optional& frustum, const glm::llvec3& offset, int density) diff --git a/src/client/world/LocalUniverse.hpp b/src/client/world/LocalUniverse.hpp index d7c4426..dfa9f7f 100644 --- a/src/client/world/LocalUniverse.hpp +++ b/src/client/world/LocalUniverse.hpp @@ -15,6 +15,8 @@ namespace world::client { ray_result raycast(const geometry::Ray &ray) const override; + bool isAreaFree(const area_ &pos, geometry::Shape shape, uint16_t radius) const override; + void getEntitiesModels(const std::function&)>&, const std::optional& frustum, const glm::llvec3& offset, int density) override; diff --git a/src/core/data/generational.hpp b/src/core/data/generational.hpp index aaaac2d..facaa90 100644 --- a/src/core/data/generational.hpp +++ b/src/core/data/generational.hpp @@ -264,6 +264,16 @@ namespace data::generational { } } + template + bool contains(predicate fn) const { + for (size_t i = 0; i < this->size(); i++) { + if(this->at(i).has_value() && fn(i, this->at(i).value())) { + return true; + } + } + return false; + } + size_t count() const { return std::count_if(this->begin(), this->end(), [](const std::optional &e) { return e.has_value(); }); diff --git a/src/core/geometry/Shapes.hpp b/src/core/geometry/Shapes.hpp new file mode 100644 index 0000000..dee20c8 --- /dev/null +++ b/src/core/geometry/Shapes.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "../flags.hpp" +#include "../data/math.hpp" +#include "IBox.hpp" + +namespace geometry { + +enum class Shape { + Cube, + Sphere +}; + +static _FORCE_INLINE_ bool InShape(Shape shape, glm::llvec3 center, int radius, glm::llvec3 pos, glm::vec3 size) { + switch (shape) { + case Shape::Cube: + return IBox::fromCenter(center, radius).contains( + IBox::fromMin(pos, size)) != IBox::ContainmentType::Disjoint; + + case Shape::Sphere: + return glm::length2(center - pos) < glm::pow2(radius + (int)size.x); + + default: + return false; + } +} + +}; diff --git a/src/core/world/Universe.hpp b/src/core/world/Universe.hpp index be5fb09..25fdf85 100644 --- a/src/core/world/Universe.hpp +++ b/src/core/world/Universe.hpp @@ -5,6 +5,7 @@ #include "Voxel.hpp" #include "position.h" #include "../geometry/Ray.hpp" +#include "../geometry/Shapes.hpp" namespace world { /// Whole abstract universe container @@ -43,6 +44,10 @@ namespace world { /// @note ray in world scale virtual ray_result raycast(const geometry::Ray &ray) const = 0; + /// Check for entity in shape + /// MAYBE: multiarea + virtual bool isAreaFree(const area_ &pos, geometry::Shape shape, uint16_t radius) const = 0; + /// Check for collision on movement bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const; /// Move with collision check diff --git a/src/core/world/actions.hpp b/src/core/world/actions.hpp index 45ccdee..405f2a4 100644 --- a/src/core/world/actions.hpp +++ b/src/core/world/actions.hpp @@ -3,6 +3,8 @@ #include "forward.h" #include "Voxel.hpp" #include +#include "../flags.hpp" +#include "../geometry/Shapes.hpp" /// Client action on world namespace world::action { @@ -17,7 +19,7 @@ struct Fill: part::Ping { const area_ pos; const Voxel val; }; -enum class Shape : uint8_t { +enum class Shape: uint8_t { Cube, Sphere, /*SmoothSphere, @@ -32,6 +34,15 @@ enum class Shape : uint8_t { ConeNZ, */ }; +static _FORCE_INLINE_ geometry::Shape ToGeometry(Shape shape) { + switch (shape) { + case Shape::Sphere: + return geometry::Shape::Sphere; + default: + return geometry::Shape::Cube; + } +} + constexpr auto SHAPES = "Cube\0Sphere\0"; struct FillShape: Fill { FillShape(const area_ &pos, const Voxel &val, Shape shape, uint8_t radius): diff --git a/src/server/world/SharedUniverse.cpp b/src/server/world/SharedUniverse.cpp index e87b9a3..9ef2763 100644 --- a/src/server/world/SharedUniverse.cpp +++ b/src/server/world/SharedUniverse.cpp @@ -15,6 +15,7 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl localHandle->entities = &entities; localHandle->emit = std::function([&](const world::action::packet &packet) { if(const auto fill = std::get_if(&packet)) { + //NOTE: LocalUniverse had already check for entities if (fill->shape == world::action::Shape::Cube) this->setCube(fill->pos, fill->val, fill->radius); else diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 1d1e0bd..975630b 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -454,7 +454,10 @@ void Universe::pullNetwork() { case client_packet_type::FILL_SHAPE: { if(const auto fill = PacketReader(packet).read()) { //TODO: check ray - //TODO: check entities + if (fill->val.is_solid() && !isAreaFree(fill->pos, world::action::ToGeometry(fill->shape), fill->radius)) { + LOG_T("Entity in solid fill area"); + break; + } //TODO: handle inventory if (fill->shape == world::action::Shape::Cube) setCube(fill->pos, fill->val, fill->radius); @@ -542,6 +545,18 @@ Universe::ray_result Universe::raycast(const geometry::Ray &ray) const { return Raycast(ray, areas); } +bool Universe::isAreaFree(const area_ &pos, const geometry::Shape shape, const uint16_t radius) const { + if (const auto it = areas.find(pos.first); it != areas.end()) { + const auto center = pos.second + it->second->getOffset().as_voxel(); + return !entities.contains([&](entity_id, const Entity &entity) { + return entity.instances.contains([&](entity_id, const Entity::Instance &inst) { + return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size); + }); + }); + } else + return false; +} + std::optional Universe::set(const area_& pos, const Voxel& val) { if(const auto it = areas.find(pos.first); it != areas.end()) { auto &chunks = it->second->setChunks(); diff --git a/src/server/world/Universe.hpp b/src/server/world/Universe.hpp index 6c8a36a..6d777d6 100644 --- a/src/server/world/Universe.hpp +++ b/src/server/world/Universe.hpp @@ -59,6 +59,8 @@ namespace world::server { /// @note ray in world scale ray_result raycast(const geometry::Ray &ray) const override; + bool isAreaFree(const area_ &pos, geometry::Shape shape, uint16_t radius) const override; + /// Check for collision on destination bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const; /// Check for collision at position