Prevent suffocation
This commit is contained in:
parent
5fdff56f8f
commit
ec467ca037
|
@ -90,6 +90,7 @@ cmake <options> ..
|
||||||
```
|
```
|
||||||
|
|
||||||
CMake options: `-DKEY=VAL`
|
CMake options: `-DKEY=VAL`
|
||||||
|
|
||||||
Key | Usage | Default
|
Key | Usage | Default
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
SIMD_LEVEL | SIMD processor acceleration (sse2, sse4.1, avx2, avx512f) | `avx2`
|
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 -->
|
<!-- CONTACT -->
|
||||||
## Contact
|
## 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)
|
||||||
|
|
5
TODO.md
5
TODO.md
|
@ -29,8 +29,8 @@
|
||||||
- Cube
|
- Cube
|
||||||
- Sphere
|
- Sphere
|
||||||
- [ ] More types
|
- [ ] More types
|
||||||
- Anchor
|
- [ ] Anchor
|
||||||
- Prevent suffocation
|
- [x] Prevent suffocation
|
||||||
- [ ] Local prediction
|
- [ ] Local prediction
|
||||||
- [~] Occlusion Culling
|
- [~] Occlusion Culling
|
||||||
- [ ] Iterator ray
|
- [ ] Iterator ray
|
||||||
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
## Hello universe
|
## Hello universe
|
||||||
|
|
||||||
|
- [ ] CI build
|
||||||
- [ ] Universe
|
- [ ] Universe
|
||||||
- [ ] Galaxy
|
- [ ] Galaxy
|
||||||
- [ ] Rotation
|
- [ ] Rotation
|
||||||
|
|
|
@ -67,7 +67,7 @@ void Client::run(server_handle* const localHandle) {
|
||||||
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
|
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
|
||||||
state.look_at = *target;
|
state.look_at = *target;
|
||||||
const auto &tool = options.editor.tool;
|
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 {
|
} else {
|
||||||
state.look_at = {};
|
state.look_at = {};
|
||||||
}
|
}
|
||||||
|
@ -79,9 +79,10 @@ void Client::run(server_handle* const localHandle) {
|
||||||
if (inputs.isPressing(Mouse::Left))
|
if (inputs.isPressing(Mouse::Left))
|
||||||
world->emit(world::action::FillShape(
|
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));
|
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(
|
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)) {
|
if (inputs.isDown(Input::Throw)) {
|
||||||
//FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
|
//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();
|
const auto pass = pipeline->beginIndicatorPass();
|
||||||
if(state.look_at.has_value()) { // Indicator
|
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 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.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();
|
pipeline->postProcess();
|
||||||
|
|
|
@ -253,6 +253,16 @@ namespace contouring {
|
||||||
}
|
}
|
||||||
ImGui::Columns(1);
|
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<render::VertexData> &tmp, Layer layer) const {
|
void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector<render::VertexData> &tmp, Layer layer) const {
|
||||||
|
|
|
@ -269,6 +269,18 @@ Universe::ray_result DistantUniverse::raycast(const geometry::Ray &ray) const {
|
||||||
return Raycast(ray, areas);
|
return Raycast(ray, areas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DistantUniverse::isAreaFree(const area_<voxel_pos> &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<void(size_t, const std::vector<glm::mat4>&)>& call,
|
void DistantUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call,
|
||||||
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)
|
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace world::client {
|
||||||
|
|
||||||
ray_result raycast(const geometry::Ray &) const override;
|
ray_result raycast(const geometry::Ray &) const override;
|
||||||
|
|
||||||
|
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
|
||||||
|
|
||||||
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
|
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
|
||||||
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;
|
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,17 @@ void LocalUniverse::emit(const action::packet &packet) {
|
||||||
Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const {
|
Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const {
|
||||||
return handle->raycast(ray);
|
return handle->raycast(ray);
|
||||||
}
|
}
|
||||||
|
bool LocalUniverse::isAreaFree(const area_<voxel_pos> &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<void(size_t, const std::vector<glm::mat4>&)>& call,
|
void LocalUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call,
|
||||||
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)
|
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace world::client {
|
||||||
|
|
||||||
ray_result raycast(const geometry::Ray &ray) const override;
|
ray_result raycast(const geometry::Ray &ray) const override;
|
||||||
|
|
||||||
|
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
|
||||||
|
|
||||||
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
|
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
|
||||||
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;
|
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,16 @@ namespace data::generational {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename predicate>
|
||||||
|
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 {
|
size_t count() const {
|
||||||
return std::count_if(this->begin(), this->end(),
|
return std::count_if(this->begin(), this->end(),
|
||||||
[](const std::optional<T> &e) { return e.has_value(); });
|
[](const std::optional<T> &e) { return e.has_value(); });
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Voxel.hpp"
|
#include "Voxel.hpp"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "../geometry/Ray.hpp"
|
#include "../geometry/Ray.hpp"
|
||||||
|
#include "../geometry/Shapes.hpp"
|
||||||
|
|
||||||
namespace world {
|
namespace world {
|
||||||
/// Whole abstract universe container
|
/// Whole abstract universe container
|
||||||
|
@ -43,6 +44,10 @@ namespace world {
|
||||||
/// @note ray in world scale
|
/// @note ray in world scale
|
||||||
virtual ray_result raycast(const geometry::Ray &ray) const = 0;
|
virtual ray_result raycast(const geometry::Ray &ray) const = 0;
|
||||||
|
|
||||||
|
/// Check for entity in shape
|
||||||
|
/// MAYBE: multiarea
|
||||||
|
virtual bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const = 0;
|
||||||
|
|
||||||
/// Check for collision on movement
|
/// Check for collision on movement
|
||||||
bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const;
|
bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const;
|
||||||
/// Move with collision check
|
/// Move with collision check
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
#include "Voxel.hpp"
|
#include "Voxel.hpp"
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include "../flags.hpp"
|
||||||
|
#include "../geometry/Shapes.hpp"
|
||||||
|
|
||||||
/// Client action on world
|
/// Client action on world
|
||||||
namespace world::action {
|
namespace world::action {
|
||||||
|
@ -17,7 +19,7 @@ struct Fill: part::Ping {
|
||||||
const area_<voxel_pos> pos;
|
const area_<voxel_pos> pos;
|
||||||
const Voxel val;
|
const Voxel val;
|
||||||
};
|
};
|
||||||
enum class Shape : uint8_t {
|
enum class Shape: uint8_t {
|
||||||
Cube,
|
Cube,
|
||||||
Sphere,
|
Sphere,
|
||||||
/*SmoothSphere,
|
/*SmoothSphere,
|
||||||
|
@ -32,6 +34,15 @@ enum class Shape : uint8_t {
|
||||||
ConeNZ,
|
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";
|
constexpr auto SHAPES = "Cube\0Sphere\0";
|
||||||
struct FillShape: Fill {
|
struct FillShape: Fill {
|
||||||
FillShape(const area_<voxel_pos> &pos, const Voxel &val, Shape shape, uint8_t radius):
|
FillShape(const area_<voxel_pos> &pos, const Voxel &val, Shape shape, uint8_t radius):
|
||||||
|
|
|
@ -15,6 +15,7 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl
|
||||||
localHandle->entities = &entities;
|
localHandle->entities = &entities;
|
||||||
localHandle->emit = std::function([&](const world::action::packet &packet) {
|
localHandle->emit = std::function([&](const world::action::packet &packet) {
|
||||||
if(const auto fill = std::get_if<world::action::FillShape>(&packet)) {
|
if(const auto fill = std::get_if<world::action::FillShape>(&packet)) {
|
||||||
|
//NOTE: LocalUniverse had already check for entities
|
||||||
if (fill->shape == world::action::Shape::Cube)
|
if (fill->shape == world::action::Shape::Cube)
|
||||||
this->setCube(fill->pos, fill->val, fill->radius);
|
this->setCube(fill->pos, fill->val, fill->radius);
|
||||||
else
|
else
|
||||||
|
|
|
@ -454,7 +454,10 @@ void Universe::pullNetwork() {
|
||||||
case client_packet_type::FILL_SHAPE: {
|
case client_packet_type::FILL_SHAPE: {
|
||||||
if(const auto fill = PacketReader(packet).read<world::action::FillShape>()) {
|
if(const auto fill = PacketReader(packet).read<world::action::FillShape>()) {
|
||||||
//TODO: check ray
|
//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
|
//TODO: handle inventory
|
||||||
if (fill->shape == world::action::Shape::Cube)
|
if (fill->shape == world::action::Shape::Cube)
|
||||||
setCube(fill->pos, fill->val, fill->radius);
|
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);
|
return Raycast(ray, areas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Universe::isAreaFree(const area_<voxel_pos> &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<world::Item> Universe::set(const area_<voxel_pos>& pos, const Voxel& val) {
|
std::optional<world::Item> Universe::set(const area_<voxel_pos>& pos, const Voxel& val) {
|
||||||
if(const auto it = areas.find(pos.first); it != areas.end()) {
|
if(const auto it = areas.find(pos.first); it != areas.end()) {
|
||||||
auto &chunks = it->second->setChunks();
|
auto &chunks = it->second->setChunks();
|
||||||
|
|
|
@ -59,6 +59,8 @@ namespace world::server {
|
||||||
/// @note ray in world scale
|
/// @note ray in world scale
|
||||||
ray_result raycast(const geometry::Ray &ray) const override;
|
ray_result raycast(const geometry::Ray &ray) const override;
|
||||||
|
|
||||||
|
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
|
||||||
|
|
||||||
/// Check for collision on destination
|
/// Check for collision on destination
|
||||||
bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const;
|
bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const;
|
||||||
/// Check for collision at position
|
/// Check for collision at position
|
||||||
|
|
Loading…
Reference in New Issue