From 686505bdeddc16db83ae725ad492bccbdbd9c607 Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 23 Oct 2020 15:19:44 +0200 Subject: [PATCH] Player's entities --- TODO.md | 9 ++- resource/content/shaders/Voxel.fs | 2 +- resource/content/shaders/Voxel.fs.spv | 4 +- resource/content/shaders/Voxel.geo.fs.spv | 4 +- resource/content/shaders/Voxel.geo.ins.fs.spv | 4 +- resource/content/shaders/Voxel.ins.fs.spv | 4 +- resource/shaders-src/Voxel.frag | 2 +- src/client/Client.cpp | 12 ++-- src/client/contouring/Abstract.hpp | 21 +++++- src/client/contouring/FlatDualMC.cpp | 20 ++++++ src/client/contouring/FlatDualMC.hpp | 4 ++ src/client/render/gl/Renderer.cpp | 1 + src/client/render/gl/api/Models.cpp | 7 ++ src/client/render/gl/api/Models.hpp | 2 + src/client/render/vk/CommandCenter.cpp | 18 +++++- src/client/render/vk/CommandCenter.hpp | 3 +- src/client/render/vk/Pipeline.hpp | 1 + src/client/render/vk/Renderer.cpp | 11 +++- src/client/render/vk/api/Models.cpp | 7 ++ src/client/render/vk/api/Models.hpp | 4 ++ src/client/world/DistantUniverse.cpp | 64 ++++++++++++++++++- src/client/world/DistantUniverse.hpp | 16 +++++ src/client/world/LocalUniverse.cpp | 20 ++++++ src/client/world/LocalUniverse.hpp | 5 ++ src/client/world/Universe.cpp | 17 ----- src/client/world/Universe.hpp | 12 +++- src/core/data/generational.hpp | 41 ++++++++++++ src/core/net/data.hpp | 13 +++- src/core/server_handle.hpp | 1 + src/model_contouring.cpp | 52 --------------- src/server/world/SharedUniverse.cpp | 1 + src/server/world/Universe.cpp | 63 +++++++++++++----- src/zstd_sampler.cpp | 63 ------------------ 33 files changed, 330 insertions(+), 178 deletions(-) delete mode 100644 src/model_contouring.cpp delete mode 100644 src/zstd_sampler.cpp diff --git a/TODO.md b/TODO.md index ccaebcf..3459500 100644 --- a/TODO.md +++ b/TODO.md @@ -25,12 +25,16 @@ - [ ] Contouring service - [~] Edit - [ ] More types + - Sphere + - Anchor + - Prevent suffocation - [ ] Local prediction - [~] Occlusion Culling - [ ] Iterator ray - [ ] Cast from chunk center - [x] Transparency - - [ ] Entities + - [~] Entities + - Get models ## Hello universe @@ -63,6 +67,7 @@ ## Hello darkness + - [ ] Break area part to entity - [ ] Slash screen - [ ] Start/Pause menu - [ ] QUIC protocal @@ -70,7 +75,7 @@ - [ ] Octree - [ ] Better Lod - [ ] VK - - [ ] Pipeline recreate + - [ ] Instanced draw - [ ] Pipeline cache - [ ] Reuse descriptors - [ ] Secondary buffers diff --git a/resource/content/shaders/Voxel.fs b/resource/content/shaders/Voxel.fs index 76be3be..2d481f0 100644 --- a/resource/content/shaders/Voxel.fs +++ b/resource/content/shaders/Voxel.fs @@ -122,7 +122,7 @@ void main() { vec3 blendWeights = abs(vs.FaceNormal_modelspace); blendWeights = blendWeights - plateauSize; - blendWeights = pow(max(blendWeights, 0), vec3(transitionSpeed)); + blendWeights = normalize(pow(max(blendWeights, 0), vec3(transitionSpeed))); vec2 UVx = vs.Position_modelspace.yz * texScale; vec2 UVy = vs.Position_modelspace.zx * texScale; vec2 UVz = vs.Position_modelspace.xy * texScale; diff --git a/resource/content/shaders/Voxel.fs.spv b/resource/content/shaders/Voxel.fs.spv index ff6cd13..7afb827 100644 --- a/resource/content/shaders/Voxel.fs.spv +++ b/resource/content/shaders/Voxel.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6887118bdf9fb9d2a6b00588618569de724df7c34e124748a32bec141a0fe5e3 -size 16868 +oid sha256:787704219c2fc0f795b26ae201ee9b46a0639b45459d56b07f258e825ccf08bc +size 16892 diff --git a/resource/content/shaders/Voxel.geo.fs.spv b/resource/content/shaders/Voxel.geo.fs.spv index f97052d..7553b71 100644 --- a/resource/content/shaders/Voxel.geo.fs.spv +++ b/resource/content/shaders/Voxel.geo.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8188855c5be7c36d0cdd6e259567ac8e825ac1593d1b024215d1b19847e96951 -size 19948 +oid sha256:22a1a0038a146f1255403ee1d1d2c78d68a64ec7ebcc3b4ffa1043ffc4d159e2 +size 19972 diff --git a/resource/content/shaders/Voxel.geo.ins.fs.spv b/resource/content/shaders/Voxel.geo.ins.fs.spv index f97052d..7553b71 100644 --- a/resource/content/shaders/Voxel.geo.ins.fs.spv +++ b/resource/content/shaders/Voxel.geo.ins.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8188855c5be7c36d0cdd6e259567ac8e825ac1593d1b024215d1b19847e96951 -size 19948 +oid sha256:22a1a0038a146f1255403ee1d1d2c78d68a64ec7ebcc3b4ffa1043ffc4d159e2 +size 19972 diff --git a/resource/content/shaders/Voxel.ins.fs.spv b/resource/content/shaders/Voxel.ins.fs.spv index ff6cd13..7afb827 100644 --- a/resource/content/shaders/Voxel.ins.fs.spv +++ b/resource/content/shaders/Voxel.ins.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6887118bdf9fb9d2a6b00588618569de724df7c34e124748a32bec141a0fe5e3 -size 16868 +oid sha256:787704219c2fc0f795b26ae201ee9b46a0639b45459d56b07f258e825ccf08bc +size 16892 diff --git a/resource/shaders-src/Voxel.frag b/resource/shaders-src/Voxel.frag index 19b2662..39ff01e 100644 --- a/resource/shaders-src/Voxel.frag +++ b/resource/shaders-src/Voxel.frag @@ -139,7 +139,7 @@ if(TRIPLANAR) { vec2 UVy = vs.Position_modelspace.zx * texScale; vec2 UVz = vs.Position_modelspace.xy * texScale; - tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights); + tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, normalize(blendWeights)); if(PBR) { // Whiteout normal blend diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 6119b1f..ed93ac2 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -183,11 +183,13 @@ void Client::run(server_handle* const localHandle) { } { // Entities const auto pass = pipeline->beginEntityPass(); - /*const auto draw = [&](const std::vector& models, buffer::Abstract *const buffer) { - reports.models_count += models.size(); - reports.tris_count += buffer->draw(pass(models)); - };*/ - //world->getEntitiesModels(draw, frustum, offset, options.voxel_density); + const auto draw = [&](size_t idx, const std::vector &models) { + if(const auto buffer = state.contouring->getEntityModel(idx)) { + reports.models_count += models.size(); + reports.tris_count += pass(buffer, models); + } + }; + world->getEntitiesModels(draw, frustum, offset, options.voxel_density); } { const auto pass = pipeline->beginIndicatorPass(); diff --git a/src/client/contouring/Abstract.hpp b/src/client/contouring/Abstract.hpp index 09d6135..be11705 100644 --- a/src/client/contouring/Abstract.hpp +++ b/src/client/contouring/Abstract.hpp @@ -4,8 +4,13 @@ #include "../../core/geometry/Frustum.hpp" #include "../../core/geometry/Ray.hpp" #include "../../core/geometry/Faces.hpp" +#include "../../core/flags.hpp" +#include -namespace render { class LodModel; } +namespace render { + class Model; + class LodModel; +} /// Mesh creation (from world to render) namespace contouring { /// Generating mesh from world data @@ -43,5 +48,19 @@ namespace contouring { /// Get buffers hitting occlusion rays with model matrices /// @note buffers invalidated after update virtual void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density, bool solid) = 0; + + /// Get buffer corresponding to entity idx + virtual render::Model* getEntityModel(size_t) = 0; + /// Get entity instance model if in frustum + static _FORCE_INLINE_ bool CullEntity(glm::mat4& out, const glm::vec3& size, const glm::vec3& scale, const glm::ifvec3& pos, + const std::optional& frustum, const glm::llvec3& offset, int density) + { + const glm::vec3 fPos = (glm::vec3(pos.raw_as_long() - offset * glm::llvec3(density)) + pos.offset) / glm::vec3(density); + if (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, size))) { + out = glm::scale(glm::translate(glm::mat4(1), fPos * (float)density), scale); + return true; + } + return false; + }; }; } \ No newline at end of file diff --git a/src/client/contouring/FlatDualMC.cpp b/src/client/contouring/FlatDualMC.cpp index 76c8b21..86b0c3f 100644 --- a/src/client/contouring/FlatDualMC.cpp +++ b/src/client/contouring/FlatDualMC.cpp @@ -60,6 +60,22 @@ namespace contouring { } }); } + + { //TODO: render for chunk(s) + auto pack = [](const glm::vec3 &pos) { + return render::PackedVertexData(meshopt_quantizeHalf(pos.x), meshopt_quantizeHalf(pos.y), + meshopt_quantizeHalf(pos.z), world::materials::textures_map[7], + meshopt_quantizeHalf(pos.x), meshopt_quantizeHalf(pos.y), + meshopt_quantizeHalf(pos.z)); + }; + playerModel = render::Model::Create(render::Model::Data({ + pack({1, 0, 0}), pack({0, 1, 0}), pack({0, 0, 1}), + pack({-1, 0, 0}), pack({0, -1, 0}), pack({0, 0, -1}) + }, { + 0, 1, 2, 0, 5, 1, 0, 2, 4, 0, 4, 5, + 1, 3, 2, 5, 3, 1, 2, 3, 4, 4, 3, 5 + })); + } } FlatDualMC::~FlatDualMC() { running = false; @@ -361,4 +377,8 @@ namespace contouring { } } + render::Model* FlatDualMC::getEntityModel(size_t) { + return playerModel.get(); + } + } diff --git a/src/client/contouring/FlatDualMC.hpp b/src/client/contouring/FlatDualMC.hpp index 271186e..3c88f06 100644 --- a/src/client/contouring/FlatDualMC.hpp +++ b/src/client/contouring/FlatDualMC.hpp @@ -38,10 +38,14 @@ namespace contouring { /// @note buffers invalidated after update void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density, bool solid) override; + render::Model* getEntityModel(size_t) override; + protected: //FIXME: use unique_ptr robin_hood::unordered_map>>> buffers; + std::unique_ptr playerModel; + safe_priority_queue_map, surrounding::corners, int, area_hash> loadQueue; safe_queue, std::pair>> loadedQueue; diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index 962bfaf..b21dc9e 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -87,6 +87,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt, const windowOption sInstance = new Renderer(opt); sInstance->setVSync(windOpt.targetFPS < Window::MIN_FPS); + Model::MakeDefault(); LodModel::MakeDefault(); return true; } diff --git a/src/client/render/gl/api/Models.cpp b/src/client/render/gl/api/Models.cpp index 675b0ac..94492a1 100644 --- a/src/client/render/gl/api/Models.cpp +++ b/src/client/render/gl/api/Models.cpp @@ -144,6 +144,13 @@ size_t LodModel::drawInstanced(size_t i) { return i * count; } +std::unique_ptr createModel(const Model::Data& data) { + return std::make_unique(data); +} +void Model::MakeDefault() { + createFunc = createModel; +} + std::unique_ptr createLodModel(const LodModel::LodData& data) { return std::make_unique(data); } diff --git a/src/client/render/gl/api/Models.hpp b/src/client/render/gl/api/Models.hpp index 7700ea3..573955a 100644 --- a/src/client/render/gl/api/Models.hpp +++ b/src/client/render/gl/api/Models.hpp @@ -42,6 +42,8 @@ public: Model(const Data&); ~Model(); + static void MakeDefault(); + size_t draw(); size_t drawInstanced(size_t count); diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index 65fa207..bfe5a82 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -315,7 +315,23 @@ size_t CommandCenter::recordModel(uint32_t i, const Subpass &worldPass, const Un vkCmdDrawIndexed(graphicsBuffers[i], size, 1, modelBuffer->getIndexStart(), 0, 0); return size; } -void CommandCenter::startEntityPass(uint32_t) { } +void CommandCenter::startEntityPass(uint32_t, const Subpass&) { } +size_t CommandCenter::recordModels(uint32_t i, const Subpass &entityPass, const std::vector &matrices, const Model *const modelBuffer) { + VkBuffer vertexBuffers[] = {modelBuffer->getVertex()}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets); + vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16); + + auto size = modelBuffer->getIndexSize(); + UniqueCurvaturePush push; + push.curvature = 0; + for(const auto& matrix: matrices) { + push.model = matrix; + vkCmdPushConstants(graphicsBuffers[i], entityPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push); + vkCmdDrawIndexed(graphicsBuffers[i], size, 1, 0, 0, 0); + } + return size * matrices.size(); +} void CommandCenter::startIndicPass(uint32_t idx, const Subpass& indicPass) { vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.pipeline); diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index 752ef7b..b140ca6 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -26,7 +26,8 @@ public: void startRecording(uint32_t idx, VkRenderPass, VkExtent2D, const VoxelUBO&); void startWorldPass(uint32_t idx, const Subpass&); size_t recordModel(uint32_t idx, const Subpass &worldPass, const UniqueCurvaturePush&, const LodModel *const); - void startEntityPass(uint32_t idx); + void startEntityPass(uint32_t idx, const Subpass &entityPass); + size_t recordModels(uint32_t idx, const Subpass &entityPass, const std::vector&, const Model *const); void startIndicPass(uint32_t idx, const Subpass&); size_t recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model); void recordPostprocess(uint32_t idx, const Subpass&, bool skybox); diff --git a/src/client/render/vk/Pipeline.hpp b/src/client/render/vk/Pipeline.hpp index 30a8c94..cdb0c1b 100644 --- a/src/client/render/vk/Pipeline.hpp +++ b/src/client/render/vk/Pipeline.hpp @@ -23,6 +23,7 @@ public: // Voxels (world & entity) passes descriptor set constexpr VkDescriptorSetLayout getVoxelDescriptorSet() const { return voxelDescriptorSet; } constexpr const Subpass& getWorldPass() const { return worldPass; } + constexpr const Subpass &getEntitiesPass() const { return worldPass; } constexpr VkDescriptorSetLayout getIndicDescriptorSet() const { return indicDescriptorSet; } constexpr const Subpass &getIndicPass() const { return indicPass; } constexpr VkDescriptorSetLayout getSkyDescriptorSet() const { return skyDescriptorSet; } diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index b899b65..e28b2a8 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -415,6 +415,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt, const windowOption } sInstance = new Renderer(instance, device, physicalInfo, opt); + Model::MakeDefault(); LodModel::MakeDefault(); return true; } @@ -471,10 +472,14 @@ std::function Rend std::function &)> Renderer::beginEntityPass() { assert(currentImage < swapChain->getImageViews().size()); - commandCenter->startEntityPass(currentImage); - return [&](render::Model *const, const std::vector&) { - return 0; //EntityPass->setup(this, models); + auto& pass = pipeline->getEntitiesPass(); + commandCenter->startEntityPass(currentImage, pass); + return [&](render::Model *const rBuffer, const std::vector& models) { + auto buffer = dynamic_cast(rBuffer); + buffer->setLastUse(currentImage); + return commandCenter->recordModels(currentImage, pass, models, buffer); }; + return [](render::Model *const, const std::vector &) { return 0; }; } std::function Renderer::beginIndicatorPass() { diff --git a/src/client/render/vk/api/Models.cpp b/src/client/render/vk/api/Models.cpp index c49a6a5..9b8911d 100644 --- a/src/client/render/vk/api/Models.cpp +++ b/src/client/render/vk/api/Models.cpp @@ -38,6 +38,13 @@ std::unique_ptr LodModel::Create(const LodData& data) { return std::unique_ptr(new LodModel(data.first.indices.size(), data.second, tmp.at(0).ref, tmp.at(1).ref, std::move(mem))); } +std::unique_ptr createModelVk(const Model::Data& data) { + return Model::Create(data); +} +void Model::MakeDefault() { + render::Model::createFunc = createModelVk; +} + std::unique_ptr createLodModelVk(const LodModel::LodData& data) { return LodModel::Create(data); } diff --git a/src/client/render/vk/api/Models.hpp b/src/client/render/vk/api/Models.hpp index 4bdfc8c..25babbd 100644 --- a/src/client/render/vk/api/Models.hpp +++ b/src/client/render/vk/api/Models.hpp @@ -71,8 +71,12 @@ protected: class Model final: public render::Model, public ShortIndexedVertexBuffer { public: + constexpr size_t getIndexSize() const { return indexSize; } + static std::unique_ptr Create(const Data &); + static void MakeDefault(); + static VkVertexInputBindingDescription getBindingDescription() { VkVertexInputBindingDescription description{}; description.binding = 0; diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index 911e207..422c59f 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -97,8 +97,9 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { } case server_packet_type::TELEPORT: { - PacketReader(packet).read(pos); - onTeleport(pos); + auto reader = PacketReader(packet); + if (reader.read(playerId) && reader.read(pos)) + onTeleport(pos); break; } @@ -199,6 +200,45 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { break; } + case server_packet_type::ENTITY_TYPES: { + entities.clear(); + auto reader = PacketReader(packet, true); + while(!reader.isFull()) { + size_t index; + glm::vec3 size; + glm::vec3 scale; + if(reader.read(index) && reader.read(size) && reader.read(scale)) { + entities.set_emplace(index, size, scale); + } + } + break; + } + + case server_packet_type::ENTITIES: { + auto reader = PacketReader(packet, true); + while(!reader.isFull()) { + size_t entity_idx; + size_t count; + if (!(reader.read(entity_idx) && reader.read(count))) + break; + + if (auto entity = entities.get(entity_idx)) { + entity->instances.clear(); + for (size_t i = 0; i < count && !reader.isFull(); i++) { + size_t idx; + glm::ifvec3 pos; + glm::vec3 vel; + if (reader.read(idx) && reader.read(pos) && reader.read(vel)) + entity->instances.set_emplace(idx, Universe::Entity::Instance{pos, vel}); + } + } else { + LOG_W("Unknown entity type " << entity_idx); + reader.skip(count * (sizeof(size_t) + sizeof(glm::ifvec3) + sizeof(glm::vec3))); + } + } + break; + } + default: LOG_W("Bad packet from server"); break; @@ -227,4 +267,24 @@ void DistantUniverse::emit(const action::packet &action) { Universe::ray_result DistantUniverse::raycast(const geometry::Ray &ray) const { return Raycast(ray, areas); +} + +void DistantUniverse::getEntitiesModels(const std::function&)>& call, + const std::optional& frustum, const glm::llvec3& offset, int density) +{ + std::vector mats; + entities.iter([&](size_t eId, const Entity &entity) { + entity.instances.iter([&](size_t iId, const Universe::Entity::Instance &inst) { + if (eId == PLAYER_ENTITY_ID.index && iId == playerId) + return; + + glm::mat4 tmp; + if (contouring::Abstract::CullEntity(tmp, entity.size, entity.scale, inst.pos, frustum, offset, density)) + mats.push_back(tmp); + }); + if(!mats.empty()) { + call(eId, mats); + mats.resize(0); + } + }); } \ No newline at end of file diff --git a/src/client/world/DistantUniverse.hpp b/src/client/world/DistantUniverse.hpp index e790010..1b8e90e 100644 --- a/src/client/world/DistantUniverse.hpp +++ b/src/client/world/DistantUniverse.hpp @@ -18,14 +18,30 @@ namespace world::client { ray_result raycast(const geometry::Ray &) const override; + void getEntitiesModels(const std::function&)>&, + const std::optional& frustum, const glm::llvec3& offset, int density) override; + bool isDisconnected() const override { return peer.isDisconnected(); } + size_t getPlayerId() const override { return playerId; } + protected: void pullNetwork(voxel_pos); /// Alive areas containing chunks area_map areas; + /// Entities without generation + struct Entity { + Entity(glm::vec3 size, glm::vec3 scale): size(size), scale(scale) { } + glm::vec3 size; + glm::vec3 scale; + data::generational::view_vector instances; + }; + data::generational::view_vector entities; + /// Player entity instance index + size_t playerId; + net::Client peer; std::optional dict; diff --git a/src/client/world/LocalUniverse.cpp b/src/client/world/LocalUniverse.cpp index 4e15dbe..a6cde3e 100644 --- a/src/client/world/LocalUniverse.cpp +++ b/src/client/world/LocalUniverse.cpp @@ -54,4 +54,24 @@ void LocalUniverse::emit(const action::packet &packet) { } Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const { return handle->raycast(ray); +} + +void LocalUniverse::getEntitiesModels(const std::function&)>& call, + const std::optional& frustum, const glm::llvec3& offset, int density) +{ + std::vector mats; + handle->entities->iter([&](entity_id eId, const Entity &entity) { + entity.instances.iter([&](entity_id iId, const Entity::Instance &inst) { + if (eId.index == PLAYER_ENTITY_ID.index && iId.index == PLAYER_ENTITY_ID.index) + return; + + glm::mat4 tmp; + if (contouring::Abstract::CullEntity(tmp, entity.size, entity.scale, inst.pos, frustum, offset, density)) + mats.push_back(tmp); + }); + if(!mats.empty()) { + call(eId.index, mats); + mats.resize(0); + } + }); } \ No newline at end of file diff --git a/src/client/world/LocalUniverse.hpp b/src/client/world/LocalUniverse.hpp index f0dde8b..d7c4426 100644 --- a/src/client/world/LocalUniverse.hpp +++ b/src/client/world/LocalUniverse.hpp @@ -15,8 +15,13 @@ namespace world::client { ray_result raycast(const geometry::Ray &ray) const override; + void getEntitiesModels(const std::function&)>&, + const std::optional& frustum, const glm::llvec3& offset, int density) override; + bool isDisconnected() const override { return !handle->running; } + size_t getPlayerId() const override { return PLAYER_ENTITY_ID.index; } + protected: server_handle *const handle; diff --git a/src/client/world/Universe.cpp b/src/client/world/Universe.cpp index f1f67b6..4c8d5c1 100644 --- a/src/client/world/Universe.cpp +++ b/src/client/world/Universe.cpp @@ -6,20 +6,3 @@ using namespace world::client; Universe::Universe(const std::string& ct): world::Universe(), contouring(std::make_unique(ct)) { } Universe::~Universe() { } - -/* -void ServerUniverse::getEntitiesModels(const std::function&, buffer::Abstract *const)> &draw, const std::optional &frustum, const glm::llvec3 &offset, int density) { - std::vector mats; - entities.iter([&](entity_id, const Entity &entity) { - entity.instances.iter([&](entity_id, const Entity::Instance &inst) { - const glm::vec3 fPos = (glm::vec3(inst.pos.raw_as_long() - offset * glm::llvec3(density)) + inst.pos.offset) / glm::vec3(density); - if (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, entity.size))) - mats.emplace_back(glm::scale(glm::translate(glm::mat4(1), fPos * (float)density), entity.scale)); - }); - if(!mats.empty()) { - draw(mats, entity.buffer.get()); - mats.resize(0); - } - }); -} -*/ \ No newline at end of file diff --git a/src/client/world/Universe.hpp b/src/client/world/Universe.hpp index 25c83bc..fd6f601 100644 --- a/src/client/world/Universe.hpp +++ b/src/client/world/Universe.hpp @@ -8,6 +8,9 @@ namespace contouring { class Abstract; } +namespace geometry { + struct Frustum; +} namespace world::client { /// Whole universe container in abstract client class Universe: public world::Universe { @@ -34,10 +37,13 @@ namespace world::client { return contouring.get(); } - virtual bool isDisconnected() const = 0; + /// Get entities in view + virtual void getEntitiesModels(const std::function&)>&, + const std::optional& frustum, const glm::llvec3& offset, int density) = 0; - //TODO: move to ClientUniverse - //void getEntitiesModels(const std::function &, buffer::Abstract *const)> &draw, const std::optional &frustum, const glm::llvec3 &offset, int density); + virtual size_t getPlayerId() const = 0; + + virtual bool isDisconnected() const = 0; protected: /// Contouring worker diff --git a/src/core/data/generational.hpp b/src/core/data/generational.hpp index 475c7b2..aaaac2d 100644 --- a/src/core/data/generational.hpp +++ b/src/core/data/generational.hpp @@ -228,6 +228,47 @@ namespace data::generational { std::vector entries; std::vector freed; }; + + template + class view_vector: public std::vector> { + public: + view_vector(): std::vector>() { } + + template + void set_emplace(size_t i, _Args &&... __args) { + if(i >= this->size()) + this->resize(i + 1); + + this->at(i).emplace(std::forward<_Args>(__args)...); + } + void set(size_t i, const T& in) { + if(i >= this->size()) + this->resize(i + 1); + + this->at(i) = in; + } + + T* get(size_t i) { + if (i >= this->size() || !this->at(i).has_value()) + return nullptr; + + return &this->at(i).value(); + } + + template + void iter(apply fn) const { + for (size_t i = 0; i < this->size(); i++) { + if(this->at(i).has_value()) { + fn(i, this->at(i).value()); + } + } + } + + size_t count() const { + return std::count_if(this->begin(), this->end(), + [](const std::optional &e) { return e.has_value(); }); + } + }; } namespace std { diff --git a/src/core/net/data.hpp b/src/core/net/data.hpp index 91a14b1..0d6e172 100644 --- a/src/core/net/data.hpp +++ b/src/core/net/data.hpp @@ -28,8 +28,8 @@ enum class server_packet_type: enet_uint8 { /// Get server salt /// reliable CHALLENGE = 0, - /// Set client position - /// voxel_pos reliable + /// Set client position and instance id + /// size_t(playerId) voxel_pos reliable TELEPORT = 1, BROADCASTED = 16, @@ -44,6 +44,15 @@ enum class server_packet_type: enet_uint8 { /// FIXME: to big !!! MAYBE: compress EDITS = 18, + /// Declare entities types + /// {size_t(index), vec3(size), vec3(scale)} reliable + /// TODO: zstd + ENTITY_TYPES = 20, + + /// Update entities instances position and velocity + /// {size_t(entity), size_t(count), {size_t(index), ifvec3(pos), vec3(velocity)}[]}[] notify + ENTITIES = 21, + /// World compression dictionary /// zstd dict reliable COMPRESSION = 24, diff --git a/src/core/server_handle.hpp b/src/core/server_handle.hpp index fedddad..b1078a3 100644 --- a/src/core/server_handle.hpp +++ b/src/core/server_handle.hpp @@ -7,6 +7,7 @@ struct server_handle { bool running = false; const world::client::area_map *areas; + const data::generational::vector *entities; std::function &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors)> onUpdate; std::function emit; std::function raycast; diff --git a/src/model_contouring.cpp b/src/model_contouring.cpp deleted file mode 100644 index 88bf0e6..0000000 --- a/src/model_contouring.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * \file model_contouring.cpp - * \brief Generate entities vertices - * \author Maelys Bois - * \version 0.0.1 - * - * Generate ShortIndexed::Data for manually defined chunks. - */ - -#include -#include "world/generator.hpp" -#include "world/Chunk.hpp" -#include "contouring/FlatDualMC.hpp" - -class Contouring: public contouring::FlatDualMC { -public: - Contouring() : FlatDualMC("iso = 0.1\nkeep_distance = 2\nload_distance = 1\nlod_levels = [ false, false, false, false, true ]\nlod_quality = 0.0\nlod_strength = 0.15\nmanifold = true\nreordering = true\ntransparency = true") { } - void render(const std::shared_ptr& chunk, buffer::LodShortIndexed::LodData& out) const { - contouring::surrounding::corners surround = { - chunk, world::EMPTY_CHUNK, world::EMPTY_CHUNK, world::EMPTY_CHUNK, - world::EMPTY_CHUNK, world::EMPTY_CHUNK, world::EMPTY_CHUNK, world::EMPTY_CHUNK - }; - std::vector tmp; - FlatDualMC::render(surround, out, tmp); - } -}; - -/// Entry point -int main(int /*unused*/, char * /*unused*/[]) -{ - const auto generator = world::generator::load(world::generator::Void::Params()); - const auto chunk = std::make_shared(chunk_pos(0), generator); - - //TODO: load from file - for (auto x = 1; x <= 6; x++) { - for (auto y = 1; y <= 6; y++) { - for (auto z = 1; z <= 6; z++) { - chunk->setAt(chunk_voxel_pos(x, y, z), world::Voxel(z >= 4 ? world::materials::ROCK : world::materials::GRASS, world::Voxel::DENSITY_MAX)); - }}} - - buffer::LodShortIndexed::LodData data; - Contouring ct = Contouring(); - ct.render(chunk, data); - assert(data.second.size() == 1 && "Must contain a single lod"); - data.first.indices.resize(data.second.front()); //Discard full res - - std::ofstream out("content/model.ivb"); - data.first.serialize(out); - out.close(); - - return 0; -} \ No newline at end of file diff --git a/src/server/world/SharedUniverse.cpp b/src/server/world/SharedUniverse.cpp index 7cb7d45..bb31e64 100644 --- a/src/server/world/SharedUniverse.cpp +++ b/src/server/world/SharedUniverse.cpp @@ -12,6 +12,7 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl movedPlayers.insert(id); localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area + localHandle->entities = &entities; localHandle->emit = std::function([&](const world::action::packet &packet) { if(const auto fill = std::get_if(&packet)) { this->set(fill->pos, fill->val); diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 9a0784f..12ffb8b 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -324,29 +324,45 @@ void Universe::update(float deltaTime) { TracyPlot("ChunkUnload", static_cast(saveQueue.size())); #endif } - /* FIXME: { // Update entities + { // Update entities ZoneScopedN("Entities"); -#if TRACY_ENABLE - size_t entity_count = 0; -#endif + size_t item_count = 0; entities.for_each([&](entity_id type, Entity &val) { - if (type == PLAYER_ENTITY_ID) //FIXME: update players - return; - val.instances.remove([&](entity_id, Entity::Instance &inst) { -#if TRACY_ENABLE - entity_count++; -#endif + if (type == PLAYER_ENTITY_ID) { + //MAYBE: update players ? + item_count++; + return false; + } + inst.pos += inst.velocity * deltaTime; - return glm::length2(glm::divide(pos - inst.pos.as_voxel())) > glm::pow2(keepDistance); + if (true /*FIXME: remove far entities ? glm::length2(glm::divide(pos - inst.pos.as_voxel())) <= glm::pow2(keepDistance);*/) { + item_count++; + return false; + } + return true; //MAYBE: Store in region ? //MAYBE: Save to files }); }); -#if TRACY_ENABLE - TracyPlot("EntityCount", static_cast(entity_count)); -#endif - }*/ + TracyPlot("EntityCount", static_cast(item_count)); + + constexpr auto CAT_SIZE = sizeof(entity_id::index) + sizeof(size_t); + constexpr auto ITEM_SIZE = sizeof(entity_id::index) + sizeof(glm::ifvec3) + sizeof(glm::vec3); + auto packet = net::Server::makePacket(net::server_packet_type::ENTITIES, NULL, CAT_SIZE * entities.size() + ITEM_SIZE * item_count, 0); + entities.iter([&](entity_id id, const Entity &entity) { + packet.write(id.index); + packet.write(entity.instances.size()); + entity.instances.iter([&](entity_id i, const Entity::Instance &inst) { + packet.write(i.index); + packet.write(inst.pos); + packet.write(inst.velocity); + }); + }); + + assert(packet.isFull()); + host.broadcast(packet.get(), net::channel_type::RELIABLE); + } { // Store loaded chunks ZoneScopedN("Load"); @@ -386,9 +402,22 @@ void Universe::pullNetwork() { host.send(peer, server_packet_type::COMPRESSION, dict_content.data(), dict_content.size(), channel_type::RELIABLE); { auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId); - host.sendTo(peer, server_packet_type::TELEPORT, player->pos.as_voxel(), channel_type::RELIABLE); + struct tp { size_t bindEntity; voxel_pos position; }; + host.sendTo(peer, server_packet_type::TELEPORT, tp{client->instanceId.index, player->pos.as_voxel()}, channel_type::RELIABLE); movedPlayers.insert(client->instanceId); } + { + constexpr auto ITEM_SIZE = sizeof(entity_id::index) + sizeof(glm::vec3) * 2; + auto packet = net::Server::makePacket(net::server_packet_type::ENTITY_TYPES, NULL, ITEM_SIZE * entities.size(), ENET_PACKET_FLAG_RELIABLE); + entities.iter([&](entity_id id, const Entity &entity) { + packet.write(id.index); + packet.write(entity.size); + packet.write(entity.scale); + }); + + assert(packet.isFull()); + host.broadcast(packet.get(), net::channel_type::RELIABLE); + } broadcastMessage("> Player" + std::to_string(client->instanceId.index) + " has joined us"); broadcastAreas(); }, @@ -424,6 +453,8 @@ void Universe::pullNetwork() { } case client_packet_type::FILL_CUBE: { if(const auto fill = PacketReader(packet).read()) { + //TODO: check ray + //TODO: check entities //TODO: handle inventory setCube(fill->pos, fill->val, fill->radius); } else { diff --git a/src/zstd_sampler.cpp b/src/zstd_sampler.cpp deleted file mode 100644 index b41c87d..0000000 --- a/src/zstd_sampler.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * \file zstd_sampler.cpp - * \brief Generate uncompressed chunks - * \author Maelys Bois - * \version 0.0.1 - * - * Generate random uncompressed chunks for Zstd dictionary training. - */ - -#include "world/Chunk.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -const auto KB = 1000; -const auto COUNT = 100; -const auto SIZE = COUNT * KB; -const auto SAMPLES = 100; -const auto RANGE = 1 << 18; - -/// Entry point -int main(int /*unused*/, char * /*unused*/[]) -{ - std::srand(std::time(nullptr)); - auto generator = world::generator::load(world::generator::Cave::Params(std::rand())); - std::vector samples; - samples.reserve(SIZE * SAMPLES); - std::vector sizes; - sizes.reserve(SAMPLES * 10); - std::cout << "Generating..." << std::endl; - std::chrono::nanoseconds gen_time(0); - while(samples.size() < SIZE * SAMPLES) { - const auto start = std::chrono::high_resolution_clock::now(); - world::Chunk chunk(chunk_pos(-(std::rand() % RANGE), -(std::rand() % RANGE), -(std::rand() % RANGE)), generator); - gen_time += (std::chrono::high_resolution_clock::now() - start); - std::ostringstream oss; - chunk.write(oss); - const auto str = oss.str(); - samples.insert(samples.end(), str.begin(), str.end()); - sizes.push_back(str.size()); - } - std::cout << gen_time.count() / sizes.size() << "ns/chunk" << std::endl; - - std::vector dict(SIZE); - std::cout << "Training on " << sizes.size() << " samples..." << std::endl; - const auto actualSize = ZDICT_trainFromBuffer(dict.data(), dict.size(), samples.data(), sizes.data(), sizes.size()); - if(ZSTD_isError(actualSize)) { - std::cout << "Error: " << ZSTD_getErrorName(actualSize) << std::endl; - return 1; - } - - std::cout << "Dictionary of " << actualSize / KB << "kb" << std::endl; - std::ofstream out("content/zstd.dict"); - out.write(dict.data(), actualSize); - out.close(); - - return 0; -} \ No newline at end of file