diff --git a/TODO.md b/TODO.md index 53f9565..acfa10f 100644 --- a/TODO.md +++ b/TODO.md @@ -25,10 +25,8 @@ - [ ] Local prediction - [ ] Contouring service - [~] Edit - - [ ] Shape iterators - - Cube - - Sphere - - [ ] More types + - [x] Shape iterators + - [ ] More shapes - [ ] Anchor - [x] Prevent suffocation - [ ] Local prediction @@ -37,11 +35,14 @@ - [ ] Cast from chunk center - [x] Transparency - [~] Entities - - Get models + - [ ] Collide + - [ ] Get models ## Hello universe - [ ] CI build + - CMake package + - GitLab / Drone pipeline - [ ] Universe - [ ] Galaxy - [ ] Rotation @@ -57,7 +58,8 @@ - https://imgur.com/kM8b5Zq - https://imgur.com/a/bh2iy - https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png - - Curvature + - [ ] Planet scale LOD + - [~] Curvature - [~] CubeSphere - [ ] Area corrected CubeSphere - [ ] Corrected Normals @@ -68,6 +70,7 @@ ## Hello industry - [ ] Multiblock + - [ ] Inventory ## Hello darkness diff --git a/src/core/geometry/Sphere.hpp b/src/core/geometry/Sphere.hpp deleted file mode 100644 index efcdcca..0000000 --- a/src/core/geometry/Sphere.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -/// Interger sphere fill -struct SphereIterator { - SphereIterator(const glm::ivec3 ¢er, int radius): center(center), radius(radius) { } - - glm::ivec3 center; - int radius; - - void vector(std::vector& out) { - int top = center.y - radius, bottom = center.y + radius; - - for (int y = top; y <= bottom; y++) { - int dy = y - center.y, dxz = floor(sqrt(radius * radius - dy * dy)); - int minx = center.x - dxz, maxx = center.x + dxz; - int minz = center.z - dxz, maxz = center.z + dxz; - out.reserve(out.size() + dxz * dxz); - for (int z = minz; z <= maxz; z++) { - for (int x = minx; x <= maxx; x++) { - out.emplace_back(x, y, z); - }} - } - } -}; diff --git a/src/core/world/actions.hpp b/src/core/world/actions.hpp index 405f2a4..11ea278 100644 --- a/src/core/world/actions.hpp +++ b/src/core/world/actions.hpp @@ -19,9 +19,10 @@ struct Fill: part::Ping { const area_ pos; const Voxel val; }; + enum class Shape: uint8_t { Cube, - Sphere, + RawSphere, /*SmoothSphere, CylinderX, CylinderY, @@ -34,16 +35,16 @@ enum class Shape: uint8_t { ConeNZ, */ }; +constexpr auto SHAPES = "Cube\0RawSphere\0"; static _FORCE_INLINE_ geometry::Shape ToGeometry(Shape shape) { switch (shape) { - case Shape::Sphere: + case Shape::RawSphere: 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): Fill(pos, val), shape(shape), radius(radius) {} diff --git a/src/core/world/iterators.cpp b/src/core/world/iterators.cpp new file mode 100644 index 0000000..f0152f6 --- /dev/null +++ b/src/core/world/iterators.cpp @@ -0,0 +1,59 @@ +#include "iterators.hpp" + +using namespace world::iterator; + +std::unique_ptr world::iterator::Get(world::action::Shape shape, uint16_t radius) { + switch (shape) { + case world::action::Shape::Cube: + return std::make_unique(radius); + case world::action::Shape::RawSphere: + return std::make_unique(radius); + default: + return std::unique_ptr(nullptr); + } +} + +bool Cube::next(pair& out) { + if (pos.z > radius) + return false; + + out.first = pos; + out.second = 1; + + // MAYBE: use linear idx to make branch less + if (pos.x < radius) { + pos.x++; + } else { + pos.x = -radius; + if (pos.y < radius) { + pos.y++; + } else { + pos.y = -radius; + pos.z++; + } + } + return true; +} + +bool RawSphere::next(pair& out) { + if (pos.x > radius) + return false; + + out.first = pos; + out.second = 1; + + if (pos.z < dz) { + pos.z++; + } else { + if (pos.y < dy) { + pos.y++; + } else { + pos.x++; + dy = floor(sqrt(radius * radius - pos.x * pos.x)); + pos.y = -dy; + } + dz = floor(sqrt(dy * dy - pos.y * pos.y)); + pos.z = -dz; + } + return true; +} \ No newline at end of file diff --git a/src/core/world/iterators.hpp b/src/core/world/iterators.hpp new file mode 100644 index 0000000..53861b6 --- /dev/null +++ b/src/core/world/iterators.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "position.h" +#include "actions.hpp" + +namespace world::iterator { + +using pair = std::pair; + +class Abstract { +public: + virtual bool next(pair&) = 0; + +protected: + static constexpr uint32_t Diam(uint16_t radius) { return radius * 2 + 1; } +}; + +/// From -radius to radius +std::unique_ptr Get(action::Shape, uint16_t radius); + +class Cube final: public Abstract { +public: + bool next(pair&) override; + + Cube(uint16_t radius): radius(radius), pos(-radius, -radius, -radius) { } + +private: + const uint16_t radius; + glm::ivec3 pos; +}; + +/// Interger sphere +class RawSphere final: public Abstract { +public: + bool next(pair&) override; + + RawSphere(uint16_t radius): radius(radius), pos(-radius, 0, 0), dy(0), dz(0) { } + +private: + const uint16_t radius; + glm::ivec3 pos; + int dy; + int dz; +}; +} \ No newline at end of file diff --git a/src/server/world/SharedUniverse.cpp b/src/server/world/SharedUniverse.cpp index 9ef2763..5ccd9ac 100644 --- a/src/server/world/SharedUniverse.cpp +++ b/src/server/world/SharedUniverse.cpp @@ -16,10 +16,7 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl 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 - this->setSphere(fill->pos, fill->val, fill->radius); + this->set(fill->pos, fill->radius, fill->shape, fill->val); } else if(const auto message = std::get_if(&packet)) { this->broadcastMessage("Player" + std::to_string(id.index) + ": " + message->text); } else if(const auto move = std::get_if(&packet)) { diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 975630b..6bdc3f1 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -7,6 +7,7 @@ #include "Chunk.hpp" #include "../../core/world/raycast.hpp" +#include "../../core/world/iterators.hpp" #include "../../core/world/actions.hpp" #include "../../core/net/PacketView.hpp" @@ -458,11 +459,8 @@ void Universe::pullNetwork() { LOG_T("Entity in solid fill area"); break; } + set(fill->pos, fill->radius, fill->shape, fill->val); //TODO: handle inventory - if (fill->shape == world::action::Shape::Cube) - setCube(fill->pos, fill->val, fill->radius); - else - setSphere(fill->pos, fill->val, fill->radius); } else { LOG_T("Bad fill"); } @@ -557,30 +555,20 @@ bool Universe::isAreaFree(const area_ &pos, const geometry::Shape sha 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(); - const auto split = glm::splitIdx(pos.second); - if(chunks.inRange(split.first)) - if(const auto chunk = chunks.findInRange(split.first)) - return {std::dynamic_pointer_cast(chunk.value())->replace(split.second, val)}; - } - return {}; -} -world::ItemList Universe::setCube(const area_& pos, const Voxel& val, int radius) { +world::ItemList Universe::set(const area_& pos, int radius, action::Shape shape, const Voxel& val) { ZoneScopedN("Fill"); ItemList list; if(const auto it = areas.find(pos.first); it != areas.end()) { robin_hood::unordered_map> edits; auto &chunks = it->second->setChunks(); - for (int z = -radius; z <= radius; z++) { - for (int y = -radius; y <= radius; y++) { - for (int x = -radius; x <= radius; x++) { - //TODO: list.pop(val) - const auto offset = voxel_pos(x, y, z); + auto iterator = world::iterator::Get(shape, radius); + world::iterator::pair point; + while (iterator->next(point)) { + const voxel_pos offset = point.first; const auto split = glm::splitIdx(pos.second + offset); - if(chunks.inRange(split.first)) + if(chunks.inRange(split.first)) { if(const auto chunk = it->second->setChunks().findInRange(split.first)) { + //TODO: use ratio in point.second auto ck = std::dynamic_pointer_cast(chunk.value()); auto prev = ck->get(split.second); if(prev.value != val.value) { @@ -591,56 +579,9 @@ world::ItemList Universe::setCube(const area_& pos, const Voxel& val, ck->replace(split.second, val, delay); } } - }}} - ZoneScopedN("Packet"); - size_t size = sizeof(area_id); - for(const auto& part: edits) { - size += sizeof(chunk_pos); - size += sizeof(chunk_voxel_idx); - size += sizeof(Chunk::Edit) * part.second.size(); - } - auto packet = net::Server::makePacket(net::server_packet_type::EDITS, NULL, size, 0); - packet.write(pos.first); - for(const auto& part: edits) { - packet.write(part.first); - packet.write(part.second.size()); - packet.write(part.second.data(), part.second.size() * sizeof(Chunk::Edit)); + } } - assert(packet.isFull()); - host.broadcast(packet.get(), net::channel_type::NOTIFY); - } - return list; -} -world::ItemList Universe::setSphere(const area_& pos, const Voxel& val, int radius) { - ZoneScopedN("FillSphere"); - ItemList list; - if(const auto it = areas.find(pos.first); it != areas.end()) { - robin_hood::unordered_map> edits; - auto &chunks = it->second->setChunks(); - for (int z = -radius; z <= radius; z++) { - for (int y = -radius; y <= radius; y++) { - for (int x = -radius; x <= radius; x++) { - const auto offset = voxel_pos(x, y, z); - //FIXME: refactor with voxel_pos iterator - if (glm::length2(offset) > glm::pow2(radius)) - continue; - - //TODO: list.pop(val) - const auto split = glm::splitIdx(pos.second + offset); - if(chunks.inRange(split.first)) - if(const auto chunk = it->second->setChunks().findInRange(split.first)) { - auto ck = std::dynamic_pointer_cast(chunk.value()); - auto prev = ck->get(split.second); - if(prev.value != val.value) { - //TODO: apply break table - //TODO: inventory - const auto delay = glm::length2(offset) / radius * .05f; - edits[split.first].push_back(Chunk::Edit{split.second, val, delay}); - ck->replace(split.second, val, delay); - } - } - }}} ZoneScopedN("Packet"); size_t size = sizeof(area_id); for(const auto& part: edits) { diff --git a/src/server/world/Universe.hpp b/src/server/world/Universe.hpp index 6d777d6..8b61023 100644 --- a/src/server/world/Universe.hpp +++ b/src/server/world/Universe.hpp @@ -3,6 +3,7 @@ #include #include #include "../../core/world/Universe.hpp" +#include "../../core/world/actions.hpp" #include "../../core/data/math.hpp" #include "../../core/data/safe_queue.hpp" #include "../../core/data/safe_priority_queue.hpp" @@ -39,14 +40,9 @@ namespace world::server { /// Apply new options void setOptions(const options &); - /// Set voxel at pos - std::optional set(const area_ &pos, const Voxel &val); - /// Set cube of voxel with pos as center + /// Set volume of voxel with pos as center /// MAYBE: allow set multi area - ItemList setCube(const area_ &pos, const Voxel &val, int radius); - /// Set sphere of voxel with pos as center - /// MAYBE: allow set multi area - ItemList setSphere(const area_ &pos, const Voxel &val, int radius); + ItemList set(const area_ &pos, int radius, action::Shape shape, const Voxel &val); /// Instante entity entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);